1. 题目
给你一个正整数的数组 A(其中的元素不一定完全不同),请你返回可在 一次交换(交换两数字 A[i] 和 A[j] 的位置)后得到的、按字典序排列小于 A 的 最大可能排列。
如果无法这么操作,就请返回原数组。
示例 1:
输入:[3,2,1]
输出:[3,1,2]
解释:
交换 2 和 1示例 2:
输入:[1,1,5]
输出:[1,1,5]
解释:
这已经是最小排列示例 3:
输入:[1,9,4,6,7]
输出:[1,7,4,6,9]
解释:
交换 9 和 7示例 4:
输入:[3,1,1,3]
输出:[1,3,1,3]
解释:
交换 1 和 3提示:
1 <= A.length <= 10000
1 <= A[i] <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/previous-permutation-with-one-swap
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题
类似题目:LeetCode 31. 下一个排列(线性扫描)
注意题目说,只能交换一次
- 新的字典序要小于A,要找一个A的 后部小的
r
跟 前面大的l
交换 - 为了最大,当后序有满足的下降时,还要更新要交换的位置(【3,1,3,1】–>【3,1,1,3】),这两个3,1,选取更靠后的下降
- 当有比左端点
l
小,但是比右端点r
大的,更新右端点(【3,1,3,1,2】–>【3,1,2,1,3】),后面的3,1,可以交换,又遇到了比 3 (l
)小,比 1 (r
)大的 2,那么更新r
为 2,获得更大的字典序
class Solution { //C++
public:vector<int> prevPermOpt1(vector<int>& A) {int i = 0, l = 0, r = 0;for(i = 1; i < A.size(); ++i){if(A[i-1] > A[i])//遇到下降, 更新, l,r越靠后越好l = i-1, r = i;//后序找到小于 A[l] 的数, 但是大于 A[r]的,// 用更大的与 l 交换,得到更大的字典序else if(A[i] < A[l] && A[i] > A[r])r = i;}swap(A[l], A[r]);return A;}
};
64 ms 23.7 MB
class Solution:# py3def prevPermOpt1(self, A: List[int]) -> List[int]:l, r = 0, 0for i in range(1,len(A)):if A[i-1] > A[i]:l, r = i-1, ielif A[i] < A[l] and A[i] > A[r]:r = it = A[l]A[l] = A[r]A[r] = treturn A
356 ms 14.9 MB