和为S的连续正数序列
OJ地址:和为S的连续正数序列
方法一:穷举(暴力解法)
求和为sum的连续子序列,可用暴力方法
算法步骤:
- 用指针 i 枚举目标序列的左边界
- 用指针 j 枚举目标序列的右边界
- 用指针 k 枚举区间 [i, j],来计算区间和,看是否等于目标sum。
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> res;
if(sum <= 2)
return res;
int tmp = 0;
for(int i = 1; i <= sum/2; i++)
{
for(int j = i; j < sum; j++)
{
tmp += j;
if(tmp == sum)
{
vector<int> path;
for(int k = i; k <= j; k++)
{
path.push_back(k);
}
res.push_back(path);
}
else if(tmp > sum)
{
tmp = 0;
break;
}
}
}
return res;
}
方法二:滑动窗口
知识补充:
- 什么是滑动窗口?
顾名思义,首先是一个窗口,既然是一个窗口,就需要用窗口的左边界i和右边界j来唯一表示一个窗口,其次,滑动代表,窗口始终从左往右移动,这也表明左边界i和右边界j始终会往后移动,而不会往左移动。
这里我用左闭右开区间来表示一个窗口。比如
- 滑动窗口的操作
- 扩大窗口,j += 1
- 缩小窗口,i += 1
【算法步骤】
- 初始化,i=1,j=1, 表示窗口大小为0
- 如果窗口中值的和小于目标值sum, 表示需要扩大窗口,j += 1
否则,如果窗口值和大于目标值sum,表示需要缩小窗口,i += 1
否则,等于目标值,存结果,缩小窗口,继续进行步骤2,3,4 - 这里需要注意2个问题:
(1) 什么时候窗口终止呢,这里窗口左边界走到sum的一半即可终止,因为题目要求至少包含2个数
(2) 什么时候需要扩大窗口和缩小窗口?解释可看上述算法步骤。
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> res;
if(sum <= 2)
return res;
int i, j;
i = j = 1; //初始化,i=1,j=1, 表示窗口大小为0
int tmp = 1;
while(i <= sum/2)
{
if(tmp < sum) //如果窗口中值的和小于目标值sum, 表示需要扩大窗口,j += 1
{
j++;
tmp += j;
}
else if(tmp == sum) //等于目标值,存结果,缩小窗口
{
vector<int> path;
for(int k = i; k <= j; k++)
path.push_back(k);
res.push_back(path);
tmp -= i;
i++;
}
else //如果窗口值和大于目标值sum,表示需要缩小窗口,i += 1
{
tmp -= i;
i++;
}
}
return res;
}