Next Permutation

一. Next Permutation

mplement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.

If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

Difficulty:Medium

TIME:26MIN

解法

这道题是求某个排列的下一个排列。何谓下一个排列,就是恰好比上一个排列大的排列,对于<1,2,3>来说,恰好比它大的排列是<1,3,2>。

因此,求某个排列的下一个排列,首先得交换两个数字。可以把交换的数字表示为left和right,left表示改变第几位,而right表示改变的数字。left的位数要尽可能的小,而且right的数字也要尽可能地小。因此left要尽可能地靠近排列的右边(越靠近右边改变的位数越小),而right是left右边中恰好比left大的数(肯定比left大,比left的小就是上一个数而不是下一个数了)。交换完之后,把left右边的数从小到大重新排序。经过这一系列的操作,就肯定得到的是一个恰好比上一个排列大的排列(刚刚好)。

如何寻找left和right呢,一开始我是遍历两遍序列(固定right,直到找到第一个比right小的数作为left)。但如果是清楚排列的性质的话,就完全有更简便的做法。排列有一个比较重要的概念就是:

  • 序列的最右边一定是一个单调增序列,而left一定是这一个单调增序列最大值的左边一个数

举例如下:

  • 对于序列<1,2,3,4>,右边的单调增序列是<4>,因此left就为3。
  • 对于序列<1,2,4,3>,右边的单调增序列是<3,4>,因此left就为2。
  • 对于序列<2,3,4,1>,右边的单调增序列是<1,4>,因此left就为3。

其实这个可以用反证法很容易地证明。另外还有一点就是left和right交换后,left右边的序列仍然是一个单调增序列(因为right是恰好大于left的数)。

void nextPermutation(vector<int>& nums) {
    int len = nums.size();
    int left = -1;
    for(int i = len - 2; i >=  0; i--) { //先寻找left
        if(nums[i] < nums[i + 1]) {
            left = i;
            break;
        }
    }
    if(left == -1) {
        reverse(nums.begin(), nums.end());
        return;
    }
    int right = 0;
    for(int i = nums.size() - 1; i > left; i--) { //然后寻找right
        if(nums[i] > nums[left]) {
            right = i;
            break;
        }
    }
    swap(nums[left],nums[right]);
    //既然left右边交换后还是一个单调增序列,那么直接反序就相当于从小到大直接排序了
    reverse(nums.begin() + left + 1, nums.end()); 
}

代码的时间复杂度为 O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值