【Leetcode HOT100】下一个排列 c++

题目描述:

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2]。
  • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 nums ,找出 nums 的下一个排列。

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

c++代码:

class Solution {
public: 
    void nextPermutation(vector<int>& nums) {
        int l = nums.size();
        if(l==1)return;
        int index_left=-1,index_right=l;
        for(int i=l-1;i>0;i--){
            //存在降序子序列
            if(nums[i-1]>=nums[i])continue;
            //不存在降序子序列 
            else if(nums[i-1]<nums[i]){
                index_left=i-1;
                for(int j=l-1;j>index_left;j--){
                    if(nums[j]>nums[index_left]){
                        index_right=j;
                        break;
                    }
                }
                if(index_right == l){ //没有更大的下一序列
                    sort(nums.begin(),nums.end());
                    return;
                }
                swap(nums[index_left],nums[index_right]);
                vector<int>::iterator it_left = nums.begin();
                for(int j=0;j<=index_left;j++){
                    it_left = it_left + 1;
                }
                sort(it_left,nums.end());
                return;
            }
        }
        if(index_left == -1){ //没有更大的下一序列
            sort(nums.begin(),nums.end());
            return;
        }
    }
};

输入序列a,直接生成目标序列b,分类讨论:

【!注意降序概念

一个降序子序列,说明该子序列已经是这个子序列的最大排序了,没有办法通过调整得到更大的子序列,若想要得到序列a的下一个更大的排序,只能考虑该子序列和其前一个数字构成的子序列。

例如序列a为(1,5,3,2,1),
则(3,2,1)是降序子序列,该子序列已经无法通过调整得到更大的排序了;

此时考虑(5,3,2,1)构成的子序列,该子序列可以通过调整得到下一个更大的子序列排序(3,1,2,5)

(1)若序列a是降序序列,则不可能有比a更大的排序方式。此时按照题目要求,应该输出序列a的最小排序。只需sort(a.begin(),a.end())

例如:a为(3,2,1)则b应为(1,2,3)

(2)若序列a不是降序序列,则从后向前查找降序子序列c,找到降序子序列前的一个数字n,对该数字n和该降序子序列c进行调整,得到下一个更大的子序列排序:在子序列c中找到比n大的最小数字m,交换n和m,此时再对新的子序列c从小到大排序,即可得到要求的序列b。

例如:a为(1,3,4,2,1),降序子序列为(4,2,1),由(3,4,2,1)构成的子序列需要调整,找到(4,2,1)中比3大的最小数3,交换4和3,再对(3,2,1)进行从小到大排序,最终得到序列b为(1,4,1,2,3)。
在这里插入图片描述

如果使用递归进行全排列,然后在所有排序结果中查找下一个序列,会超时,超时代码:

class Solution {
public:
    //全排列
    void Perm(vector<int> nums,int k,int m,vector<vector<int>> &res){
        //如果要排序的数字只有一个(k=m时),只对nums[k]排序,则已经产生一个排序序列结果
        if(k==m){
            //记录当前排序
            vector<int> this_res;
            for(int i=0;i<=m;i++){
                this_res.push_back(nums[i]);
            }
            //查找当前排序是否和之前记录的排序重复,若不重复则记录该排序,否则不记录
            if(!count(res.begin(),res.end(),this_res)){ 
                res.push_back(this_res);
            }
        }
        else{
            for(int i=k;i<=m;i++){
                swap(nums[k],nums[i]);//依次把第k个数字换到最前面
                Perm(nums,k+1,m,res);//已经把第k个数字换到最前面,只需对后面的数组递归地排序
                swap(nums[k],nums[i]);//完成递归排序后,恢复原来的顺序,以便下一次换第k个数字到最前面
            }
        }
    }
    void nextPermutation(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> prenums = nums; //防止在递归过程中nums改变,要记录出入的初始nums
        int l = nums.size();
        if(l==1)return;
        Perm(nums,0,l-1,res);
        sort(res.begin(),res.end()); //对所有的排序结果,进行字典排序
        for(int i=0;i<res.size();i++){ //在所有排序结果中查找nums的位置
            if(prenums == res[i]){  
                if(i==res.size()-1)nums=res[0]; //若nums是字典序最大的排序,输出第一个(字典序最小的排序
                else{ //若nums不是字典序最大的排序,输出它后面的下一个排序
                    nums=res[i+1];
                    break;

                }
            }
        }
    }
};

总结:

序列问题,首先考虑有特点的子序列,注意降序子序列升序子序列

找到一种调整方法,通过调整,直接求出要求的序列。使用列出全部排列结果的方法会超时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值