您的位置:首页 > 其它

和为n的连续正数序列

2012-08-27 12:37 253 查看
【题 目】输入一个整数,输出所有和为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/。对解题思路有任何建议,欢迎在评论中告知。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: