力扣P31 解析

力扣P31 解析

题干

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

解答

为了能够找到下一个更大数,首先考虑特殊情况,数列中不存在前后一个比后一个小的逆序对,即全升序时,直接反转即可;
若存在这样一个逆序对,则我们希望变换后的数增幅最小,很自然的想法是从后往前找这样一个数,这个数是第一个逆序对,即它之后的数,每个都比后一个数大,比如[1,3,4,5,3,2],下标为2的数4,就是第一个逆序对的位置,因为4<5,而5之后都是依次递减。
之后我们这样考虑,从后往前看,[3,2]不能够产生更大的数,[5,3,2]也不能,[4,5,3,2]数列则可以产生一个更大的数。又由于4之后的数是递增的,在后面的数之间进行移动无法产生更大的数,因而只能将4和之后的某个数替换位置,为了使新的数增幅最小,因而在之后挑选出比4大的中最小的数,即4,然后将4和5两个数调换位置,得到[5,4,3,2],但为了得到增幅最小的,需要对之后的数重排,由于尾部的数一定是按序的,只要反转即可。

// An highlighted block
class Solution {
public:
    void nextPermutation(vector<int>& nums) {    
        if(nums.size()==1)  return ;//长度为1,直接返回
        bool flag=false;
        for(int i=0;i<nums.size()-1;i++)  {if(nums[i]<nums[i+1])  {flag=true;break;}}
        if(!flag)  {
            cout<<"sort"<<endl;
            sort(nums.begin(),nums.end());      //没有逆序对,直接排序即可
            return ;      
        }
        int tmax=nums[nums.size()-1];//有逆序对,找到最尾部的逆序对,tmax记录尾部的最大值
        int t=0;
        for(int i=nums.size()-2;i>=0;i--)
        {
            if(nums[i]<tmax){ t=i;break;}
            else tmax=max(tmax,nums[i]);
        }//此时t记录第一个出现逆序对的位置
        int minn=10e8,s=0;
        for(int i=nums.size()-1;i>t;i--) if(nums[i]>nums[t]&&nums[i]<minn) {minn=nums[i]; s=i;}//找到比num[t-1]大的最小的数
        int temp=nums[t];//交换minn和t位置
        nums[t]=nums[s];
        nums[s]=temp;
        for(int i=t+1,j=nums.size()-1;i<=j;i++,j--)
        {//反转尾部数组
            int temp=nums[i];
            nums[i]=nums[j];
            nums[j]=temp;
        }        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值