【题 目】输入一个整数,输出所有和为n的连续正数序列。例如:输入15,由于15=7+8=4+5+6=1+2+3+4+5,所以输出的序列为『1,2,3,4,5』;『4,5,6』,『7,8』三个。
【思路1】从等差数列的观点考虑:如果有一列数满足i+(i+1)+...+j=n,根据等差数列的求和公式,我们容易得到:(i+j)(j-i+1)/2=n,即(i+j)(j-i+1)=2n,由于i,j均为正整数,我们容易得到(i+j),(j-i+1)也都为正整数,所以都是2n的因子,我们就可以从2到sqrt(2n)遍历2n的所有因子,对于其中的因子k,我们有:
我们只需要保证j,i的值都为整数,并且i<j即可。根据这种思路我们有如下的代码:
1 #include<iostream>
2 #include<string>
3 #include<cmath>
4 using namespace std;
5
6 void FindContinuousSequence(int n)
7 {
8 int half = (int)(sqrt(2*n));
9 for(int k = 2;k <= half;++k)
10 {
11 //找到因子k
12 if((2*n) % k == 0)
13 {
14 int temp1 = 2 * n - k*k + k;
15 int temp2 = 2 * n + k*k - k;
16
17 //开始数start,结束数end都为整数
18 if(temp1 % (2*k) == 0 && temp2 % (2*k) == 0)
19 {
20 int start = temp1 / (2*k);
21 int end = temp2 / (2*k);
22
23 //打印从start到end之间的所有数
24 for(int i = start;i <= end;++i)
25 cout<<i<<"\t";
26
27 cout<<endl;
28 }
29 }
30 }
31 }
32
33 int main()
34 {
35 cout<<"Enter your Number:"<<endl;
36 int number = 0;
37 cin >>number;
38
39 cout<<"the sum equals your number is:"<<endl;
40 FindContinuousSequence(number);
41 return 0;
42 }
运行结果如下:
容易看出,这种算法需要遍历的范围是从2—sqrt(2n),因而时间复杂度为O(sqrt(n)),效率还算是比较高的,然而缺点是要计算很多的乘除,乘方运算,对于n值较大输入,计算过程会相对较慢。
【思路2】我们从另一角度考虑这个问题,我们根据【算法10】中从两端想中间夹逼求解的基本思想,可以这样考虑:我们用一个small指示序列中最小值,用big指示序列中的最大值,因为和为n的序列至少需要两个数字,因而small取值从1到中点;如果small+big<n,就让big后移,以此增大sum;而如果small+big>n,就让small前移,以此缩小sum;如果small+big==n,打印从small到big之间的所有值即可。基于这种思路的代码为:
1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5 void FindContinuousNumbers(int n)
6 {
7 int small = 1;
8 int big = 2;
9 int middle = (n + 1)/2;
10 int sum = small + big;
11 while(small < middle)
12 {
13 if(sum == n)
14 {
15 for(int i = small;i <= big;++i)
16 cout<<i<<"\t";
17 cout<<endl;
18 }
19
20 while(sum > n)
21 {
22 sum -=small;
23 small++;
24
25 if(sum == n)
26 {
27 for(int i = small;i <= big;++i)
28 cout<<i<<"\t";
29
30 cout<<endl;
31 }
32
33 }
34
35 big++;
36 sum += big;
37 }
38 }
39
40 int main()
41 {
42 cout<<"Enter your Number:"<<endl;
43 int number = 0;
44 cin>>number;
45
46 cout<<"The sum equals your number is as following:"<<endl;
47 FindContinuousNumbers(number);
48
49 return 0;
50 }
运行结果如下图:
效率分析:small指针要从1开始遍历到middle,而big指针则对于每一个small指针一直往前遍历,不存在指指针回溯的情况,因而整个算法的时间复杂度为O(N),效率较之前的算法的低,然而所有的操作都是简单的加减法,相比之前需要大量的乘法运算是一个优势。
References:
何海涛博客:http://zhedahht.blog.163.com/blog/static/25411174200732711051101/
注:
1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。
2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。