Leetcode.31下一个排列

题目

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

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

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

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

思路

从后往前遍历数组,将数组分为两个部分 [ 0, i ] 以及 [ t, hi ],在后一部分中找到比 nums[ i ] 大的第一个元素,与之交换后,再将 [ t , hi ] 中的元素以升序输出。注意,在索引 i 从后往前遍历的过程中, [ t, hi ] 可始终保持降序的有序性,原因:只有比 [ t, hi ] 的所有元素都大才会被插入至 [ t, hi ] 的最前端。实现如下:

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
            if(nums.empty())
                return;
            int hi=nums.size()-1;
            if(nums.size()<=2){
                swap(nums[0], nums[hi]);
                return;
            }
            int t=hi+1, i=hi;
            //至少有三个元素
            for(; i>=0; i--, t--){
                if(t==nums.size())
                    continue;
                //查找[t, hi]之间第一个大于nums[i]的元素
                int j=search(t, hi, nums[i], nums);
                
                if(j==-1){//没有找到相应的元素
                    if(i==0)//字典最大序的情况
                        reverse(0, hi, nums);
                    continue;
                }else{
                    swap(nums[i], nums[j]);
                    reverse(t, hi, nums);
                    break;
                }
            }
    }
    int search(int lo, int hi, int target, vector<int>& nums){
        if(target>nums[lo])
            return -1;
        //线性查找
        for(int i=hi; i>=lo; i--){
            if(nums[i]>target)
                return i;
        }        
        return -1;
    }
    void reverse(int lo, int hi, vector<int>& nums){
        while(lo<hi){
            swap(nums[lo], nums[hi]);
            lo++, hi--;
        }
    }
};

由于是有序数组,所以可以在查找效率上进行提升(二分查找注意,1、搜索区间确定 [ lo, hi ]。2、索引移动后对其它区间的影响。3、返回索引是否越界可以看其增长方向):

    int search(int lo, int hi, int target, vector<int>& nums){
        int t=lo;
        while(lo<=hi){//令索引小于 lo 的元素全部大于nums[lo],索引大于hi的元素全部小于等于nums[hi]
            int mi=lo+(hi-lo)/2;
            if(nums[mi]<target)
                hi=mi-1;
            else if(target<nums[mi])
                lo=mi+1;
            else if(target==nums[mi])
                hi=mi-1;
        }
        //终止时, lo元素必定不大于 target或者越界(为nums.size()),而lo-1必定大于target或者越界(lo从未增长过)
        if(lo==t)
            return -1;
        return lo-1;
    }
发布了18 篇原创文章 · 获赞 0 · 访问量 786

猜你喜欢

转载自blog.csdn.net/afiguresomething/article/details/104730627