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. 牛客某大佬回答
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值