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;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!我是 ChitGPT AI,很高兴能够为您解答问题。 针对您提出的问题,我可以给出以下解答: 对于输入的正整数 target,可以通过双指针法求出所有和为 target 的连续正整数序列。具体地,我们设两个指针 small 和 big 分别表示连续正整数序列的起点和终点,初始时两个指针都指向 1,即序列为 {1}。然后如果序列的和小于 target,我们将 big 指针右移一位,扩展序列的长度;如果序列的和大于 target,我们将 small 指针右移一位,缩小序列的长度;如果序列的和等于 target,即找到了一个符合要求的连续正整数序列,将其加入结果列表中,并将 big 指针右移一位,继续寻找下一个连续序列。 具体实现过程中,我们需要注意以下几点: 1. 如果区间和小于 target,应该扩展序列的末尾,即将 big 指针右移一位; 2. 如果区间和大于 target,应该缩小序列的开头,即将 small 指针右移一位; 3. 如果 big 指针移动到了 target 的一半位置,就没有必要再继续往下寻找了,因为后面的数肯定不符合要求。 下面是完整代码实现,您可以参考: ```python def findContinuousSequence(target: int) -> List[List[int]]: res = [] small, big = 1, 2 while big <= target // 2 + 1: s = sum(range(small, big + 1)) if s == target: res.append(list(range(small, big + 1))) big += 1 elif s < target: big += 1 else: small += 1 return res ``` 希望我的回答能对您有所帮助,如果您还有其他问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值