分享一道奇妙的力扣题---下一个排列

该文章介绍了如何解决LeetCode中的‘下一个排列’问题,通过从后向前遍历数组,找到第一个降序位置,然后反向查找并交换最小大于前一个数的元素,最后反转剩余部分,以达到最小增大的排列。这种方法避免了使用排序,从而将时间复杂度降低到O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

31. 下一个排列 - 力扣(LeetCode)

 我们要做的就是让左边一个较小的数与右边一个较大的数进行交换,而且,要让 ”较小的数尽可能靠近右边,而较大的数尽可能的小“

而且再交换之后,要让i到n-1上的数字从小到大,这一点很重要,只有这样才能保证变大的幅度最小

 越靠右的话改变的位置越小,十位的变动肯定比百位,千位引起的变化小的多

改变的时候,肯定是想又能变大,又尽可能的变大的比较少

有了这些基础我们就可以来写这道题了:

我们先从后向前,去找第一个出现nums[ i-1 ] < nums[ i ] 的情况,那么在i到n-1的区间上,肯定是降序的,因为都不满足前面的条件嘛,所以说我们可以从后面的区间   i 到 n-1上 从后向前去找到到第一个元素j,满足nums[ i-1 ]  < nums[ j ],然后交换这两个数的值

交换之后这个这个区间也还是降序的,我们只需要翻转reverse一下就能得到升序,这个复杂度也是O(n),如果用sort的话复杂度是O(nlogn)。外面一次遍历是O(n),内部一次翻转,这两个是并列的,相当于最多进行两次遍历,也就是2 * O(n),也就是说时间复杂度能够达到O(n),实在是妙哉!

//两次扫描
    void nextPermutation(vector<int>& nums) {
        int n=nums.size();
        for(int i=n-1;i>0;--i){
            if(nums[i-1]<nums[i]){//找到第一个i-1 < i的位置
                //i到n-1上肯定是降序
                //从i到n-1上从后向前找到第一个满足nums[i-1]<nums[j]的数,这个数就是这里面最小的,而且大于nums[i-1]的数,交换以后这个区间还是降序的,reverse之后就能满足升序
                for(int j=n-1;j>=i;--j){
                    if(nums[i-1]<nums[j]){
                        int tmp=nums[i-1];//交换
                        nums[i-1]=nums[j];
                        nums[j]=tmp;
                        //翻转    i 到 n-1 这个区间,就能让这个区间升序
                        //sort(nums.begin()+i,nums.end())
                        reverse(nums.begin()+i,nums.end());
                        return;
                    }
                }
            }
        }
        //如果没有返回则说明需要从到到尾翻转
        reverse(nums.begin(),nums.end());
    }

当我们用sort的时候:

而我们用了reverse的话:

 

 可以看到,reverse是真的秒啊

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值