题意
找到下一个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)