lintcode第51/52题 上、下一个排列

描述

给定一个整数数组来表示排列,找出其之后的一个排列。

排列中可能包含重复的整数

样例

给出排列[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就是数组外的数了,而“下一个排列”却通过了所有的测试。。。。

好吧,在这两句之间加个判断即可



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值