【剑指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;
}
};
总结
这类问题一般需要保留两个指针,通过对两个指针的移动来逐渐向条件靠拢,两个指针的初始值选择很关键。