Problem: 31. 下一个排列
问题描述
“下一个排列” 的定义是:给定数字序列的字典序中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
我们可以将该问题形式化地描述为:给定若干个数字,将其组合为一个整数。如何将这些数字重新排列,以得到下一个更大的整数。如 123 下一个更大的数为 132。如果没有更大的整数,则输出最小的整数。
以 1,2,3,4,5,6 为例,其排列依次为:
123456
123465
123546
…
654321
可以看到有这样的关系:123456 < 123465 < 123546 < … < 654321。
必须原地修改,只允许使用额外常数空间。
解题过程
-
暴力求解,但是题目要求原地修改+常数空间;
-
排序
“下一个排列”,即为更大的数,需要比较前后位置的大小关系。
对于132654,下一个数为134256,观察数列发现,需要从后往前比较,找到最小的数nums[i],使得[i,size)为降序。
132654已无变大的可能性,只能从132654着手,将后面的4与之交换,也就是从后往前遍历,找到最小的数,记索引为i,再从i到末尾寻找最后一个比nums[i]大的数,即这里的4。
找到后与之交换,得到134652,652依然保持降序,但我们希望得到不那么大的数,需要对652进行反转操作,得到134256。
如果在第一次遍历时找不到更小的数,说明当前整个数组为一个降序顺序,已经是最大,需要对整体进行反转操作,例如654321,得到123456。
STL解法
根据维基百科:
- 先找出最大的索引 k 满足 nums[k] < nums[k+1],如果不存在,就翻转整个数组;
- 再找出另一个最大索引 l 满足 nums[l] > nums[k];
- 交换 nums[l] 和 nums[k];
- 最后翻转 nums[k+1:end]。
Code
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int index = -1; //第一遍遍历
for(int i=nums.size()-1;i>0;i--){
if(nums[i]>nums[i-1]){
index=i-1;
break;
}
}
if(index==-1){ //如果没找到,则整体反转,并返回结果
//翻转
int i =0;int j =nums.size()-1;
while(i<j){
swap(nums[i++],nums[j--]);
}
return;
}
int cmp=-1; //如果找到,则进行第二次遍历
for(int i=nums.size()-1;i>0;i--){
if(nums[i]>nums[index]){
cmp=i;
break;
}
}
swap(nums[index],nums[cmp]); //交换数字
int i =index+1;int j =nums.size()-1; //反转操作
while(i<j){
swap(nums[i++],nums[j--]);
}
return;
}
};