问题导入
对一个给定的自然数M,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为M。
例如:1998 + 1999 + 2000 + 2001 + 2002 = 10000,所以从1998到2002的一个自然数段为M = 10000的一个解。
输入格式
第一行,一个整数M。
输出格式
每行两个自然数,给出一个满足条件的连续自然数段中的第一个数和最后一个数,
两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,
对于给定的输入数据,保证至少有一个解。
数据范围
10 ≤ M ≤ 2, 000, 000,连续自然数段的长度至少为2.
例如输入:10000
输出:18 142
297 328
388 412
1998 2002
双指针
如果用for(int i=0;i<m;i++)
for(int j=i+1;j<m;j++)暴力方法
当x加到y恰好等于m时,我们要退出第二个循环
但是我们m=4000,如果sum再加上2000就超过了m,这个时候继续加下去没有意义。我们要停止第二个循环
并且让i加上1,那么问题又来了,我们又需要再次让sum从i+1开始遍历,显然暴力方法超时
显然会超时
我们借助双指针,当sum大于m的时候,我们让x指针右移,当sum小于m的时候,我们让x指针左移
#include <stdio.h>
int main()
{
//设置两个指针x,y
//一个指向左边,一个右边
//sum值为x+(x+1)+(x+2)+……+(y-1)+(y)
int m, x = 1, y = 2, sum = 3;//然后初始让sum值为x+y
//m为0,1,2时候无连续自然数对
scanf("%d", &m);
while (y <= m / 2 + 1) {//结束条件是右指针到一半加1
//eg.例如m是5时候,右边最多遍历到3,因为最少需要两个自然数
if (sum < m) {//当小于时,就将右指针扩大
y++;
sum += y;
}
else if (sum == m) {//等于就输出,并且继续扩大右边
printf("%d %d\n", x, y);
y++;
sum += y;
}
else {//大于就扩大左指针,将x去掉,然后x变为x+1
sum -= x;
x++;
}
}
return 0;
}