LeetCode_Next Permutation

Posted rotk2015

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode_Next Permutation相关的知识,希望对你有一定的参考价值。

  1. 字典序全排列问题,该系列的核心问题是,如何从一个字典序的排列生成下一个最小排列。例如,12543 的下一个最小排列是,13245。

  2. 我们可以这么考虑,排列从左到右的每个数位,对应不同的权重。其中,最左边的权重最大,最右的权重最小(右至左如同个、十、百、千…);而给定的数字,如同砝码。那么这个问题翻译过来就是,生成下一个总重量大于当前重量的排列,且该排列在所有可能的结果中,总重量最小(说白了就是重一点意思一下得了)。

  3. 那么,给定数字 1 2 3 4 5,它的所有排列中,最小的、最大的分别是什么?这个问题很简单,我们要求最小的,只要让小砝码在大权重上,大砝码在小权重上就行了;要求最大的,那就反过来,大砝码在大权重上,小砝码在小权重上(这是整个算法的核心!)。

  4. 考虑刚刚举的例子,凭什么 12543 的下一个最小排列就是 13245 呢?我们是如何从 12543 演变到 13245 的呢?

  5. 注意到,12543 的后半段 543 是递减的。这意味着,在前两位 1 2 不动的前提下,后三位 3 4 5 已经取到了最大值 543,要再增加总重量,就得往前引入一个新的砝码了(老人都到极限了,要拉新人下水)。那么,拉谁呢?选 1 的话,2 就会占最高位;选 2 的话,1就会占最高位。显然选后者,因为我们只想重一点,按照第3条中的思想,要让大砝码在小权重上折腾,才能整体最小,所以我们拉 2 下水。

  6. 好的,现在我们将 1 扔到一边去不管他,考虑如何从 2543 演变至它的下一全排列。首先,2 肯定不能在最高位了,别忘了,2 在最高位的情况下,543 已经是最大值了,而我们要求下一个的总重量要更重,所以,我们拉 2 下水之后,还要安排一个比它更重的人顶它的位置。那么,我们选谁上位呢?由于后三位必是递减趋势(原因参照第5条,极限),所以我们从后往前数找到第一个比 2 大的数(必定存在(除非是边界),且必定是比 2 大的数中最小的),3。这么做的原因参照第5条,我们只想重一点

  7. 好了,现在 3 顶替了2上位,那么,2 该安排到哪里呢?考虑 3 上位前,是老人中的最小值,且已经在它所能在的最低位,它右边的数,没有比 2 更重的。所以,我们先让 2 待在 3 原来的位置,其他数保持原位不动,那么我们会获得一个比原来的 543 轻一点的配置:542,但这已经是 2 4 5 的极限了。下一步,由于 13 已经保证比 12 高了(且只是高一点),那么,我们只需保证让剩下的是最轻的配置,做法很简单,将新官 3 后边的数,全部逆序,即可得 245。最终拼接一下,得到 13245。

  8. 总结一下,算法分三步:

    1. 从右至左找到第一个元素 arr[i],使得 arr[i] < arr[i+1]。(对应第5条)
    2. 从右至左找到第一个元素 arr[j],使得 arr[i] < arr[j]。交换两者。(对应第6条,以及第7条的前半部分)
    3. 将从arr[i+1]到最右端的所有元素逆序。(对应第7条的后半部分)
  9. 代码如下:

    import java.util.ArrayList;
    import java.util.Arrays;
    public class Solution 
        public ArrayList<String> Permutation(String str) 
            ArrayList<String> lis = new ArrayList<>();
            if(str==null || str.length()==0)
                return lis;
            char[] cArr = str.toCharArray();
            Arrays.sort(cArr);
            lis.add(new String(cArr));
            helper(cArr, lis);
            return lis;
        
        private void helper(char[] arr, ArrayList<String> lis)
            int len = arr.length;
            int i = len-2;
            for(; i>=0 && arr[i]>=arr[i+1]; i--);
            if(i<0)
                return;
            int j = len-1;
            for(; j>=0 && arr[i]>=arr[j]; j--);
            swap(arr, i, j);
            for(int lef=i+1, rig=len-1; lef<rig; lef++, rig--)
                swap(arr, lef, rig);
            lis.add(new String(arr));
            helper(arr, lis);
        
        private void swap(char[] arr, int a, int b)
            char tmp = arr[a];
            arr[a] = arr[b];
            arr[b] = tmp;
        
    
    

参考资料

  1. 牛客某大佬回答

以上是关于LeetCode_Next Permutation的主要内容,如果未能解决你的问题,请参考以下文章

prev_permutation()和next_permutation()

STL中关于全排列next_permutation以及prev_permutation的用法

STL next_permutation和prev_permutation函数

全排列 ( next_permutation)

LeetCode31 Next Permutation and LeetCode60 Permutation Sequence

[算法]——全排列(Permutation)以及next_permutation