[LeetCode] 1053. Previous Permutation With One Swap

Given an array of positive integers arr (not necessarily distinct), return the lexicographically largest permutation that is smaller than arr, that can be made with exactly one swap (A swap exchanges the positions of two numbers arr[i] and arr[j]). If it cannot be done, then return the same array.

Example 1:

Input: arr = [3,2,1]
Output: [3,1,2]
Explanation: Swapping 2 and 1.

Example 2:

Input: arr = [1,1,5]
Output: [1,1,5]
Explanation: This is already the smallest permutation.

Example 3:

Input: arr = [1,9,4,6,7]
Output: [1,7,4,6,9]
Explanation: Swapping 9 and 7.

Example 4:

Input: arr = [3,1,1,3]
Output: [1,3,1,3]
Explanation: Swapping 1 and 3.

Constraints:

  • 1 <= arr.length <= 104
  • 1 <= arr[i] <= 104

交换一次的先前排列。

给你一个正整数的数组 A(其中的元素不一定完全不同),请你返回可在 一次交换(交换两数字 A[i] 和 A[j] 的位置)后得到的、按字典序排列小于 A 的最大可能排列。

如果无法这么操作,就请返回原数组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/previous-permutation-with-one-swap
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这道题有两种思路,一种会利用到 treemap,一种是线性解法。这道题有点像在找下一个 permutation,但是这个 permutation 还不是下一个,而是比当前 input 给的 permutation 小的所有 permutation 里面最大的那个。

这道题的核心在于无论是哪种做法,都必须是从右往左扫描 input 数组,从左往右是不行的。首先 treemap 的做法,对于当前的 input 数组给的 permutation,如果我们要找一个比他小的 permutation,我们首先需要找到一个下降的地方,比如第一个例子里的3 - 2,然后我们将 2 替换成比 2 小的数字里最大的那个(如果有的话)。按照这个例子就是 1。所以我们可以反过来思考,我们从右往左扫描,对于当前的数字,如果 treemap 里存在一个 lowerKey,那么就把当前数字和 lowerKey 进行 swap 即可。

时间O(nlogn)

空间O(n)

Java实现

 1 class Solution {
 2     public int[] prevPermOpt1(int[] arr) {
 3         TreeMap<Integer, Integer> map = new TreeMap<>();
 4         int len = arr.length;
 5         map.put(arr[len - 1], len - 1);
 6         for (int i = arr.length - 2; i >= 0; i--) {
 7             Integer lower = map.lowerKey(arr[i]);
 8             if (lower != null) {
 9                 int j = map.get(lower);
10                 swap(arr, i, j);
11                 break;
12             }
13             map.put(arr[i], i);
14         }
15         return arr;
16     }
17 
18     private void swap(int[] arr, int i, int j) {
19         int temp = arr[i];
20         arr[i] = arr[j];
21         arr[j] = temp;
22     }
23 }

 

再来是线性的解法。刚才 treemap 的解法是利用到 treemap 自动排序的特点。这里我们线性的解法则可以省去这个排序的步骤。还是从右往左扫描,按照题意我们需要找一个拐点。如果扫描下去一直是下坡的话(arr[i - 1] < arr[i]),则一直往下走;当我们找到一个拐点的时候,则停下,此时的 arr[i - 1] 是参与 swap 的元素之一。此时我们再次从右往左扫描,找到的第一个比 arr[i - 1] 小的元素是参与 swap 的另一个元素。把两者 swap 即可。

时间O(n)

空间O(1)

Java实现

 1 class Solution {
 2     public int[] prevPermOpt1(int[] arr) {
 3         int len = arr.length;
 4         int a = len - 1;
 5         int b = len - 1;
 6         for (int i = len - 1; i >= 1; i--) {
 7             if (arr[i - 1] > arr[i]) {
 8                 a = i - 1;
 9                 break;
10             }
11         }
12 
13         for (int i = len - 1; i > a; i--) {
14             if (arr[i] == arr[i - 1]) {
15                 continue;
16             }
17             if (arr[i] < arr[a]) {
18                 b = i;
19                 break;
20             }
21         }
22         swap(arr, a, b);
23         return arr;
24     }
25 
26     private void swap(int[] arr, int i, int j) {
27         int temp = arr[i];
28         arr[i] = arr[j];
29         arr[j] = temp;
30     }
31 }

 

LeetCode 题目总结

[LeetCode] 1053. Previous Permutation With One Swap

上一篇:noip40


下一篇:命令操作