Given an array of positive integers arr
(not necessarily distinct), return the <span data-keyword="lexicographically-smaller-array">lexicographically</span>* largest permutation that is smaller than* arr
, that can be made with exactly one swap. If it cannot be done, then return the same array.
Note that a swap exchanges the positions of two numbers arr[i]
and arr[j]
For example:
arr = [3,2,1]
should return [3,1,2]
because swapping 2 and 1 makes a smaller array.arr = [1,1,5]
should return [1,1,5]
because this is already the smallest permutation.arr = [1,9,4,6,7]
should return [1,7,4,6,9]
because swapping 9 and 7 makes a smaller array.## Problem Description
Given an array of positive integers `arr` (not necessarily distinct), the goal is to find the lexicographically largest permutation that is smaller than the input array `arr`, achievable with exactly one swap. If no such permutation exists, the function should return the original array.
## Brute Force Solution
A brute-force approach would involve generating all possible permutations of the array by swapping two elements at a time. Then, among all generated permutations, we find the largest one which is smaller than the original array.
```python
import itertools
def find_permutation_brute_force(arr):
best_permutation = None
for i in range(len(arr)):
for j in range(i + 1, len(arr)):
temp_arr = arr[:]
temp_arr[i], temp_arr[j] = temp_arr[j], temp_arr[i]
if temp_arr < arr and (best_permutation is None or temp_arr > best_permutation):
best_permutation = temp_arr[:]
return best_permutation if best_permutation else arr
# Example usage
arr = [1, 9, 4, 6, 7]
print(find_permutation_brute_force(arr)) # Output: [1, 7, 4, 6, 9]
Time Complexity: O(n^2) to iterate through all possible swaps and O(n) to copy the array for each swap, resulting in O(n^3). Additionally, comparison of arrays may take O(n). So, the overall complexity is approximately O(n^3).
Space Complexity: O(n) for storing the temporary array temp_arr
and best_permutation
.
This solution is inefficient and not optimal.
The optimal solution involves scanning the array from right to left and finding the first element that is greater than the element to its right. Let's call the index of this element 'i'. Then, scan the array from right to left again from index 'i + 1' to the end and find the largest element smaller than arr[i]. Swap these two elements.
def find_permutation(arr):
n = len(arr)
# Find the index i such that arr[i] > arr[i+1]
i = n - 2
while i >= 0 and arr[i] <= arr[i + 1]:
i -= 1
# If no such i exists, the array is non-increasing, return original array
if i == -1:
return arr
# Find the index j of the largest element to the right of i that is smaller than arr[i]
j = n - 1
while j > i and arr[j] >= arr[i]:
j -= 1
# Swap arr[i] and arr[j]
arr[i], arr[j] = arr[j], arr[i]
return arr
# Example usage
arr = [1, 9, 4, 6, 7]
print(find_permutation(arr)) # Output: [1, 7, 4, 6, 9]
arr = [3, 2, 1]
print(find_permutation(arr)) # Output: [3, 1, 2]
arr = [1, 1, 5]
print(find_permutation(arr)) # Output: [1, 1, 5]
The algorithm iterates through the array at most twice. The first loop finds the index i
, which takes O(n) time. The second loop finds the index j
, which also takes O(n) time. The swap operation takes O(1) time. Therefore, the overall time complexity is O(n).
The algorithm uses a constant amount of extra space, regardless of the size of the input array. The space is used for variables such as i
, j
, and n
. Therefore, the space complexity is O(1).
[5, 4, 3, 2, 1]
), no swap will produce a lexicographically smaller permutation. The algorithm correctly identifies this case by checking if i
is -1 after the first loop and returns the original array.[1, 2, 2, 3]
). The second loop finds the rightmost largest element smaller than arr[i]
, ensuring the lexicographically largest permutation.i
will remain -2, and i == -1
will become true.