题意
找到下一个permutation是什么,对于一个数组[1,2,3],下一个排列就是[1, 3, 2]
链接
https://leetcode.com/problems/next-permutation/
思考
首先任何一个permutation满足一个性质,从某个位置往后一定是降序
。
比如[2,1,4,3]这么一个排列,3和4之间是没有办法交换的了,因为此时已经达到了[2,1]开头的最大值,只能改变1才能够变成一个更大排列。
解法
所以步骤分为三步:
记n为num.size();
- 从右往左找,找到位置i,使得nums[i-1] < nums[i]
- 此时nums[i-1]是我需要交换的其中元素,我需要在下标区间[i, nums.size()-1]中找到最后一个大于nums[i-1]的元素,和nums[i-1]交换
- 把[i,n]这个区间的元素升序排列
解法
//最终优化版本
int i = nums.size() - 1;
while( i > 0 && nums[i-1] >= nums[i]) i--;
if (i == 0) {
reverse(nums.begin(), nums.end());
return;
}
int l = i;
int r = nums.size() - 1;
int t = nums[i-1];
//二分找到最后一个严格大于nums[i-1]的值
while(l < r) {
int mid = l + (r - l)+1 / 2;
if(nums[mid] > t) {
l = mid;
} else {
r = mid - 1;
}
}
//这里不需要判断答案是否存在,因为while( i > 0 && nums[i-1] >= nums[i]) i--;已经保证了二分一定有值,至少有一个元素是比nums[i-1]要大
//交换两个数
swap(nums[i-1], nums[l]);
//把从第i位开始的数字到末尾升序排列
reverse(nums.begin()+i, nums.end());
算法复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
//没有用二分的版本
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size()-2;
for(; i >= 0; i--) {
if(nums[i] < nums[i+1])
break;
}
if (i == -1) {
return reverse(nums.begin(),nums.end());
}
int j = nums.size()-1;
for(; j >= 0; j--) {
if(nums[j] > nums[i]) {
swap(nums[j], nums[i]);
break;
}
}
return reverse(nums.begin()+i+1, nums.end());
}
};
算法复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)