LeetCode刷题笔记--31. Next Permutation

31. Next Permutation

Medium

1601489FavoriteShare

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 and use only constant 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

读完这道题的题目,完全不知道在讲什么,字典序到底是什么东西??

网上很多资料都是直接贴答案,但是读懂题目才是正确解题的第一步,搜了很久,感谢有人讲清楚了:

https://blog.csdn.net/yimi1995/article/details/77115866

但是这位作者的答案和题目讲解差异很大,感觉也不对啊。所以我又重新看了网页中solution的部分,终于搞懂是什么情况了。

这里的字典序:lexicographically是指全排列的顺序。

讲个例子,就懂了。

比如数组:1,2,3

将这个数组作全排列后得到下面的各种可能(下面就是按照字典序的排列)

1,2,3

1,3,2

2,1,3

2,3,1

3,1,2

3,2,1

也就是说按照字典序的排列中有什么特点呢?就是上图从纵向看:按照从低位[0]到高位[size()-1]递增

然后我百度了一下全排列:https://baike.baidu.com/item/%E5%85%A8%E6%8E%92%E5%88%97/4022220?fr=aladdin

这里面有介绍,顺便复习一下:

全排列数f(n)=n!(定义0!=1)

以下介绍全排列算法四种:

(A)字典序

(B)递增进位制数法

(C)递减进位制数法

(D)邻位对换法

因此要找到这个排列在字典序中的下一个排列,方法是:从后往前找,先找到两个相邻的位a[i],a[i+1],他们的关系是:a[i]<a[i+1]。此时a[i]右边的数(不含a[i])都是降序排列的,在a[i]右边的数(不含a[i])中,找到正好比a[i]小(小的最少)的数a[j],将a[i]和a[j]交换。此时a[i]和a[j]的位置对了,但是还不是字典序中下一个排列,还需要做一步,就是将a[i]右边的数(不含a[i])做升序排列,这样就最小了。

solution中的animation图画得不错,讲得很清楚:

 

Next Permutation

 

Next Permutation

下面是C++ AC的代码:

class Solution {
public:
    void swap(vector<int>& nums,int i,int j)
    {
        int m=nums[i];;
        nums[i]=nums[j];
        nums[j]=m;
        return;
    }
    
    void decrease(vector<int>& nums,int start)
    {
        int end=nums.size()-1;
        while(start<end)
        {
            swap(nums,start,end);
            start++;
            end--;
        }
        return;
    }
    
    void nextPermutation(vector<int>& nums) {
        int i=nums.size()-2;
        while(i>=0&&nums[i]>=nums[i+1])
        {
            i--;
        }
        if(i>=0)
        {
            int j=nums.size()-1;
            while(j>=0&&nums[j]<=nums[i])
            {
                j--;
            }
            swap(nums,i,j);
        }
        decrease(nums,i+1);
        return;
            
    }
};

还有个地方想特别记录一下,就是为什么 while(i>=0&&nums[i]>=nums[i+1])和while(j>=0&&nums[j]<=nums[i])中都是用了>=,<=,为什么不是>,<,为什么要加=。

第一个 while(i>=0&&nums[i]>=nums[i+1]),在这种case下[1,1,1]我们希望直接i--到-1,即不用操作,直接return。第二个没想到理由,感觉应该可以不用加=。

另外,为什么[1],[]这种可以不用特别写出来呢,[1],i=-1,然后到 decrease(nums,i+1);时变成了(nums,0)。[]的情况变成了(nums,-1),到decrease函数中,end=-1,start=-1,不用做什么,直接return了,因此不会报错。

看了答案后,自己写的时候才会发现这么多细节的问题。总得来说,这道题有点难的。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值