【中等】31-下一个排列 Next Permutation
题目
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
解法
解题思路
如果没有下一个排列,那么一定是从大到小的有序序列,如果有下一个排列,那么一定可以将序列分成两部分:无序的前缀和有序的最大后缀,如对于9,4,7,6,5,3,2来说,从后向前,2,3,5,6,7是有序后缀,9,4是前缀,那么下一个要排列一定是把前缀的最后一位4换成后缀中比4大且最接近的5,且新后缀是从小到大排序的,可以使用一个序列把后缀23567存起来,找到5之后再把23467放回原来后缀的位置,5放到原来的4的位置(官方方法交换45之后翻转)
代码
代码一:queue
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int size = nums.size(), change = 0, changenum = 0;
if(size <= 1) return;
queue<int> ord;
for(change = size-1; change > 0; --change){
ord.push(nums[change]);
if(nums[change-1] < nums[change]){
change = change-1;
changenum = nums[change];
break;
}
}
cout << change << changenum << endl;
if(change == 0 && nums[0] >= nums[1]){
int currpos = 0;
nums[size-1] = nums[0];
while(!ord.empty()){
nums[currpos++] = ord.front();
ord.pop();
}
return;
}
bool find = false;
int currpos = change+1;
while(!ord.empty()){
int newnum = ord.front();
if(newnum > changenum && !find){
find = true;
nums[currpos++] = changenum;
nums[change] = newnum;
}
else nums[currpos++] = newnum;
ord.pop();
}
}
};
代码二:交换
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int size = nums.size(), change = -1, changenum = 0;
if(size <= 1) return;
queue<int> ord;
for(int i = size-2; i >=0; --i){
if(nums[i]<nums[i+1]){
change = i;
break;
}
}
if(change != -1){
for(int i = change+1; i < size; ++i){
if(nums[i] <= nums[change]){
swap(nums[i-1], nums[change]);
break;
}
else if(i == size-1){
swap(nums[i], nums[change]);
break;
}
}
}
int l = change+1, r = size-1;
while(l < r){
swap(nums[l], nums[r]);
l++;
r--;
}
}
};
Email:1252418308@qq.com