时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思路:
- 在该题讨论区中发现了这种思路,采用了所谓的双指针技术,相当于有了个窗口,窗口的左右两边就是两个指针,根据窗口内数值和的情况来确定窗口的位置以及宽度。
比如:
输入sum = 20,遍历1,2,3,...,18,19,20
- 定义两个指针leftP,rightP,左指针leftP指向1,右指针rightP指向2,先固定leftP不动,rightP依次往后遍历求和sumVal,直到rightP的值大于sum的值,遍历循环结束
- 当sumVal < sum :rightP++,并sumVal加上当前值;当sumVal > sum时:要先sumVal减去leftP,再leftP++更新leftP数据;当sumVal == sum:则将leftP和rightP这个区间内的数值存储到vector容器中;
- 要求输出所有的和为S的连续正序列,则仍需要继续往下进行。rightP++,sumVal+=rightP,直到循环条件不满足
class Solution {
public:
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> saveRe;
if(sum <= 0)
return saveRe;
int leftP = 1;
int rightP = 2;
int sumVal = leftP + rightP;
while(sum > rightP)
{
if(sumVal < sum)
{
rightP++;
sumVal += rightP;
}
else if(sumVal > sum)
{
sumVal -= leftP;
leftP++;
}
else
{
vector<int> saveElem;
for(int i = leftP;i <= rightP;i++)
{
saveElem.push_back(i);
}
saveRe.push_back(saveElem);
rightP++;
sumVal += rightP;
}
}
return saveRe;
}
};
- 另一种解法虽然也是使用了双指针,但巧妙之处在于总结道该连续数列为公差为1的等差数列,因此利用等差数列的求和公式,使代码更加简洁、清晰,也再次体现出数学的魅力
class Solution {
public:
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> saveRe;
if(sum <= 0)
return saveRe;
int leftP = 1;
int rightP = 2;
while(leftP < rightP)
{
//由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2
int sumVal = (leftP+rightP)*(rightP - leftP +1)/2;
if(sumVal < sum)
{
rightP++;
}
else if(sumVal > sum)
{
leftP++;
}
else
{
vector<int> saveElem;
for(int i = leftP;i <= rightP;i++)
{
saveElem.push_back(i);
}
saveRe.push_back(saveElem);
rightP++;
}
}
return saveRe;
}
};