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

扫描二维码关注公众号,回复: 6140752 查看本文章

但是这位作者的答案和题目讲解差异很大,感觉也不对啊。所以我又重新看了网页中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了,因此不会报错。

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

猜你喜欢

转载自blog.csdn.net/vivian0239/article/details/89083237