[leetcode刷题] 和为s的连续正数序列

题目传送门

1.滑动窗口

因为结果是连续序列,所以可用头哨兵尾哨兵来唯一确定一个序列。序列的和也可以计算出。因此有n*n个序列需要去判断。
但是当知道了某序列的值已经比target要大,则相同起点更长的序列不需要判断,所以可以剪枝掉一部分,因此有滑动窗口一说。

具体流程:
序列初始为[1]其值为1(如果是0会错)。
小于target时头走一步(可根据增量来计算出新序列的值)
大于target时尾走一步
相等时记录(两者任意走一步即可)

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        
        //record
        vector<vector<int>> result;
        int sum = 1;

        //boundary 
        int l = 1;
        int r = 1;
        int sidx = 1;
        int eidx = target/ 2 + 1;

        //main
        while (l <= r && r <= eidx){
            if (sum == target){
                //cout<<1<<endl;
                vector<int> tmp_vec;
                for(int i = l; i <= r; i++)
                    tmp_vec.push_back(i);
                result.push_back(tmp_vec);
                sum -= l++;
                sum += ++r;
            } else if (sum < target){
                //cout<<2<<endl;
                sum += ++r;
            } else if (sum > target){
                //cout<<3<<endl;
                sum -= l++;
            }
        } 
        return result;
    }
};

2.计算

因为所求为连续序列,可以设序列中位数为x,数量为n,则target=n*x
奇数序列时,中位数就是序列中间的数
偶数序列时,中位数就是序列中间两个数的平均值,可以认定是两者中较小的数字+0.5
(tips:当target翻倍时,中位数是整数)
所以在某个确定的长度n下,可以通过计算算出是否有序列存在。
而n的边界的话,因为初始化序列为[1],则n应该从1开始增加,最大值为可能出现的最长的序列。
最长的序列应该是从1开始到x,其值为(x+1)*x/2

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        
        //record
        vector<vector<int>> result;
        int n = 1;

        //boundary 
        int limit = sqrt(target*2) + 1;

        //main
        while ( ++n <= limit ){
            if( (n%2==1 && target%n==0) || 
                (n%2==0 && target%n!=0 && target*2%n==0) ){ //奇数列 中位数是整数  偶数列 中位数是0.5小数

                int mid = target / n;
                vector<int> tmp_vec;
                if( n%2 == 1 ){ //奇数序列
                    for (int i = mid - (n-1)/2; i <= mid + (n-1)/2 ;i++)
                        tmp_vec.push_back(i);
                }else {
                    for (int i = mid - (n-1)/2; i <= mid + (n-1)/2 + 1 ;i++)
                        tmp_vec.push_back(i);
                }
                if(tmp_vec[0] != 0)
                    result.push_back(tmp_vec);
            }
        }
        reverse(result.begin(), result.end());
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值