两种方法解LeetCode和为s的连续正数序列

题目描述在这里插入图片描述

方法一:数学方法

头一次自己想的方法不仅能通过,而且效率还挺高,先看一下数学方法的提交结果
在这里插入图片描述
其实思路也很简单:分析题目可知得到的序列为等差数列,那我们只要知道每个序列的起始值以及序列的长度,我们就可以构造出整个序列,然后用一个临时的vector保存此序列,最后将临时的vector加入二维数组(vector<vector> res)即可

  • 首先确定序列的大小,序列的大小为 [2,sqrt(2*target)]
    • 因为当序列起始值为1时构造序列,序列长度最长,由等差数列公式可知此时长度就是sqrt(2*target)
  • 有了序列的长度n,又有了等差数列的和target,现在就可以求得数列的起始值,然后构造数列了。起始值s,数列长度n,目标值target三者满足如下关系才可构造数列
    ( 2 ∗ s + n − 1 ) ∗ n / 2 = t a r g e t \quad\quad\quad\quad\quad\quad(2*s+n-1)*n/2 = target (2s+n1)n/2=target
    • 此时要想完美地求得数列的起始值,我们需要
      2 ∗ t a r g e t / n 2* target/n 2target/n ( 2 ∗ t a r g e t / n + 1 − n ) / 2 (2*target/n+1-n)/2 (2target/n+1n)/2 同时为整数,满足此条件就可以构造等差数列了

附上代码:

vector<vector<int>> findContinuousSequence(int target) {
    
    
        vector<vector<int>> res;
        for(int n=(int)sqrt((double)target*2); n>=2; n--){
    
    
            if(2*target%n==0 && (2*target/n+1-n)%2==0){
    
    
                int s = (2*target/n+1-n)/2;//s表示数列起始值
                if(s < 1) continue;//起始值必须为正整数
                vector<int> temp;
                int len = n;
                while(len-- > 0){
    
    
                    temp.push_back(s++);
                }
                res.push_back(temp);
            }
        }
        return res;
    }

方法二:滑动窗口

也挺好理解的,我就不写分析过程了,参考题解:滑动窗口

int getSum(int left , int right){
    
    
    int res = 0;
    for(int i=left; i<=right; i++){
    
    
        res += i;
    }
    return res;
}
vector<vector<int>> findContinuousSequence(int target) {
    
    
    vector<vector<int>> res;
    int left = 1;
    int right = left + 1;
    while( left <= target/2 ){
    
    
        int sum = getSum(left, right);
        if(sum < target){
    
    
            right++;
            continue;
        }else if(sum > target){
    
    
            left++;
            continue;
        }else{
    
    
            vector<int> temp;
            for(int i=left; i<=right; i++){
    
    
                temp.push_back(i);
            }
            res.push_back(temp);
            left++;
            right++;
        }
    }
    return res;
}

不用每次调用getsum函数的代码

vector<vector<int>> findContinuousSequence(int target) {
    
    
        vector<vector<int>> res;
        int left = 1;
        int right = left + 1;
        int sum = getSum(left, right);
        while( left <= target/2 ){
    
    
            if(sum < target){
    
    
            	//先移动右侧窗口再修改sum值
                right++; 
                sum += right;//此时的区间和
            }else if(sum > target){
    
    
            	//先修改sum值,再移动左侧窗口
                sum -= left;
                left++;
            }else{
    
    
                vector<int> temp;
                for(int i=left; i<=right; i++){
    
    
                    temp.push_back(i);
                }
                res.push_back(temp);
                sum -= left;
                left++;//窗口左边界向右移动
                right++;//由于左边界移动了,显然右边界也要向右移动
                sum += right;
            }
        }
        return res;
    }

猜你喜欢

转载自blog.csdn.net/qq_42500831/article/details/105351721