【力扣刷题】【1-50】【快慢指针】31. 下一个排列

31. 下一个排列

1.寻找规律,构造算法

  • 因为题目要求我们不使用额外空间,因此我们不能构造出所有序列并且排序,需要根据当前序列直接推断出结果。

  • 如果没有见过这样的题目,直接设计出优秀算法难度是比较大的,可以直接学一下题解中的优秀方法。如果不好理解力扣题解的描述,可以看看我下面的分析:

  • 本题需要我们根据构造序列的规律,构造出符合条件的序列。我们假设自己没见过任何相关算法,试着分析一下这个问题:

    • 假设给出的数字是123654,我们要怎么写出下一个比它大的序列?
    • 不难发现后面三个数字654是完全倒序的,这就是6、5、4这三个数字可以组合成的最大序列。也说明123开头可以形成的最大序列也就是123654,123这个前缀已经走到头了。
    • 寻找新前缀:我们为了找到仅仅比123大一点点的新前缀,就需要从后面的456里找出比3大的最小的数字——4,新前缀就是124。
    • 交换位置:我们交换3、4的位置,新数字为124653;但我们注意到这并不符合要求,653并不是这三个数字构成的最小数。
    • 排序:因此我们将后面三个数字排序,使它变为356,124356就是123654的下个数字。
  • 我上面的分析假设了一个前缀、后缀的分界线,在123、654之间,我们接下来只需要找到方法确定其他情况的这个分界,整个算法就完备了。

  • 这个“前缀”是从前往后遍历,最后一个nums[ind]<nums[ind+1]的位置,这个位置正是当前需要变大一点点的位置,也是增大幅度可以最小的位置。我们在这里只要从后往前找,第一个满足条件的位置即可。

  • 注意,找到这个位置之后,ind之后的后半部分全部是倒序的,因此排序的部分,只要反转即可,就完成了从小到大的排序。

    class Solution {
    public:
        void nextPermutation(vector<int>& nums) {
            int ind1=nums.size()-2,ind2=nums.size()-1;
            //寻找第一个满足nums[ind1]小、nums[ind1+1]大的位置
            while(ind1>=0&&nums[ind1]>=nums[ind1+1]){
                ind1--;
            }
            //如果知道最后都没有找到符合条件的ind1,说明已经形成了最大的数字,直接将数组整个反转。
            if(ind1>=0){
                while(ind2>=0&&nums[ind2]<=nums[ind1]){
                    ind2--;
                }
                swap(nums[ind1],nums[ind2]);
            }
            reverse(nums.begin()+ind1+1,nums.end());
        }
    };
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值