【剑指Offer-知识迁移能力】面试题57.2:和为s的连续整数序列

题目描述

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
注:该题是由面试题57:和为s的两个数字拓展而来。

思路

因为是连续子序列的和,所以连续子序列的范围很重要,假设范围为[left, right]。我们将left初始化为1, right初始化为2。首先求范围[left, right]的和sum(left, right),如果sum(left,right)==s,那么意味着找到了一个范围[left, right],然后增加right,继续寻找下一个范围;如果sum(left, right)<s,则需要增大big,使范围包含更多数字;如果sum(left, right)>s,则需要增大left,缩小范围,使得范围中的数字减少,从而降低和。重复上面的过程直至left>s/2。因为序列长度至少为2,right至少比left大1,当left=(1+s)/2,left+right>s,此时已经不符合要求了,所以循环终止。代码如下:

class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        int left = 1;
        int right = 2;
        int mid = (1+sum)/2;
        int curSum = left+right;
        vector<vector<int>> ans;
        
        while(left<mid){
            if(curSum==sum){
                vector<int> v = getVector(left, right);
                ans.push_back(v);
            }
            while(curSum>sum && left<mid){
                curSum-=left;
                left++;
                
                if(curSum==sum){
                    vector<int> v = getVector(left, right);
                    ans.push_back(v);
                }
            }
            right++;
            curSum+=right;
        }
        return ans;
    }
    
    vector<int> getVector(int left, int right){
        vector<int> v;
        for(int i=left; i<=right; i++)
            v.push_back(i);
        return v;
    }
};

总结

这类问题一般需要保留两个指针,通过对两个指针的移动来逐渐向条件靠拢,两个指针的初始值选择很关键。

原文地址:https://www.cnblogs.com/flix/p/12525735.html