描述
给定一个整数数组来表示排列,找出其之后的一个排列。
排列中可能包含重复的整数
样例
给出排列[1,3,2,3]
,其下一个排列是[1,3,3,2]
给出排列[4,3,2,1]
,其下一个排列是[1,2,3,4]
看到题目是懵逼的,完全不明白啥意思,看了看讨论才明白是字典排序。
思考后发现,该题目等价于“不考虑极值的情况下,在排列中寻找比当前排列大的最小的数。”
那么上一个排列也就等价于“不考虑极值的情况下,在排列中寻找比当前排列小的最大的数。”
接下来考虑解法。
遇事不决举个例子:
7 6 3 4 5 2 1 下一个
7 6 3 5 1 2 4 下一个
7 6 3 5 1 4 2
…………
7 6 3 5 4 2 1 下一个
7 6 4 1 2 3 5 下一个
7 6 4 1 2 5 3
似乎找到规律了,
1.从右向左历遍,找第一个降序的地方,降序说明这个位置可以变大。
2.从找到的位置向右历遍,找到比它大的最小值与之交换。
3.因为找到的这个位置右边都是升序的,就将这个位置右边的变为最小的排序。可简化为整体前后翻转。
完成
过程有了,接下来的就是转换成代码了。
编码还是比较简单的,下一个排列:
class Solution {
public:
/**
* @param nums: A list of integers
* @return: A list of integers
*/
void swap(vector<int> &nums, int i, int j) {
int temp;
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
void overturn(vector<int> &nums, int i, int j) {
while (i < j)
{
swap(nums, i, j);
i++;
j--;
}
}
vector<int> nextPermutation(vector<int> &nums) {
// write your code here
if (nums.size()<2)
{
return nums;
}
int i = nums.size() - 2;
while (i>=0&&nums[i]>=nums[i+1])
{
i--;
}
if (i<0)
{
overturn(nums, 0, nums.size() - 1);
return nums;
}
int j = i+1;
while (nums[i]<nums[j+1])
{
j++;
}
swap(nums, i, j);
overturn(nums, i + 1, nums.size() - 1);
return nums;
}
};
上一个排列也是相同思路,先举例,把前边的例子反过来看就好:
7 6 3 4 5 2 1 下一个
7 6 3 5 1 2 4 下一个
7 6 3 5 1 4 2
…………
7 6 3 5 4 2 1 下一个
7 6 4 1 2 3 5 下一个
7 6 4 1 2 5 3
流程也出来了,拷贝过来改一下:
1.从右向左历遍,找第一个升序的地方,升序说明这个位置可以变小。
2.从找到的位置向右历遍,找到比它小的最大值与之交换。
3.因为找到的这个位置右边都是降序的,就将这个位置右边的变为最小的排序。可简化为整体前后翻转。
完成
class Solution {
public:
/*
* @param nums: A list of integers
* @return: A list of integers that's previous permuation
*/
void swap(vector<int> &nums, int i, int j) {
int temp;
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
void overturn(vector<int> &nums, int i, int j) {
while (i < j)
{
swap(nums, i, j);
i++;
j--;
}
}
vector<int> previousPermuation(vector<int> &nums) {
// write your code here
if (nums.size()<2)
{
return nums;
}
int i = nums.size() - 2;
while (nums[i]<=nums[i+1])
{
i--;
}
if (i<0)
{
overturn(nums, 0, nums.size() - 1);
return nums;
}
int j = i+1;
while (nums[i]>nums[j+1])
{
j++;
}
swap(nums, i, j);
overturn(nums, i + 1, nums.size() - 1);
return nums;
}
};
上边的代码改几个<>号就行了,但是运行时出了错:
[1,2,1]
[1,0,1]
[1,1,2]
查看代码,果然,在
int j = i+1;
while (nums[i]>nums[j+1])
这里存在越界的可能,如果i为倒数第2个数,j+1就是数组外的数了,而“下一个排列”却通过了所有的测试。。。。
好吧,在这两句之间加个判断即可