[Leetcode] Next Permutation

题目:

Implement 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


思路:网上有很多比较详细的描述。具体做法是从右向左找到第一个不符合递增的数字,例如15876432,那么从右向左第一个不递增的数字是5. 然后从右向左找到第一个比5大的数,这里是6,交换5和6,得到16875432,这个时候将6后面的数字reverse即可,得到16234578.

        比较直观的解释是,对于next permutation,总是优先改变后面的数字,然后再改变前面的数字,例如12345,首先会对1后面的4个数字进行递增,直到15432,接下来才改变1,这就是为什么要从右向左做。另外可以看到,5432已经没有没有可以重新排列变成更大的数的可能了,因此需要一直找到一个不满足递增的数字A。注意到数字A的右边全部是递减的(或者说从右向左递增)。找到以后,再次的从右向左,找到第一个比这个数字大的数字B。因为A右边都是递减的,继续向左走只可能更大,因此B是A右边比A大的数中最小的数。现在的情况是...... A ...... B ......,交换A和B,得到...... B ...... A ......。注意到我们是从右向左找的,B是第一个比A大的数,因此A目前的位置的右边不可能有比A大的数,同时B ~ A 的区间内的数都是比B大的(因为递增),因此也比A大。所以,B后面的数字是从左向右递减的,如上面例子16875432,6后面的数字。这个时候,因为最高位(6)增大了,因此后面的部分需要重新排列成为最小,才是next permuation. 因此需要重新排列。

        需要注意的是,可能原数组已经是倒序了,例如321,那么下一个排列必须是重新再来,所以直接reverse,形成最小。


class Solution {
public:
    void swap(int& a, int& b) {
        int temp = b;
        b = a;
        a = temp;
    }
    
    void nextPermutation(vector<int> &num) {
        int front = -1;
        int len = (int)num.size();
        // find the first number violates increasing order from right to left
        for (int i = len - 1; i > 0; --i) {
            if (num[i] > num[i-1]) {
                front = i - 1;
                break;
            }
        }
        if (front < 0) {   //ready biggest, reverse the array
            for (int i = 0; i < len / 2; ++i) {
                swap(num[i], num[len-1-i]);
            }
        } else {
            int back = len - 1;
            // find the first number that is bigger than num[front]
            for (int i = len - 1; i > front; --i) {
                if (num[i] > num[front]) {
                    back = i;
                    break;
                }
            }
            // swap the two numbers
            swap(num[front], num[back]);
            // the array after num[front] must be decreasing
            // reorder to increasing order to guarantee smallest
            for (int i = 1; i <= (len - front) / 2; ++i) {
                swap(num[front+i], num[len-i]);
            }
        }
    }
};


总结:复杂度为O(n).

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值