和為N的連續正整數序列
題目
輸入一個正整數數N,輸出所有和為N連續正整數序列。例如輸入15,由於1+2+3+4+5=4+5+6=7+8=15,所以輸出3個連續序列1-5、4-6和7-8。
一種運用數學規律的解法
假定有k個連續的正整數和為N,其中連續序列的第一個數為x,則有x+(x+1)+(x+2)+...+(x+k-1) = N。從而可以求得x = (N - k*(k-1)/2) / k。當x的值小於等於0時,則說明已經沒有正整數序列的和為N了,此時迴圈退出。初始化k=2,表示2個連續的正整數和為N,則可以求出x的值,並判斷從x開始是否存在2個連續正整數和為N,若不存在則k++,繼續迴圈。
-
bool find_sequence(
- {
- bool has = false;
- int k = 2, x, m ; //k為連續序列的數目,x為起始的值,m用於判斷是否有滿足條件的值。
- while (true) {
- x = (N - k*(k-1)/2) / k; //求出k個連續正整數和為N的起始值x
- m = (N - k*(k-1)/2) % k; //m用於判斷是否有滿足條件的連續正整數值
- if (x <= 0) break; //退出條件,如果x<=0,則迴圈退出。
-
if (!m) {
- has = true;
- output(x, k);
- }
- k++;
- }
- return has;
- }
- void output(int x, int k)
- {
- for (int i=0; i<k; i++) {
- cout << x++ << " ";
- }
- cout << endl;
- }
擴充套件
問題:是不是所有的正整數都能分解為連續正整數序列呢?
答案:不是。並不是所有的正整數都能分解為連續的正整數和,如32就不能分解為連續正整數和。對於奇數,我們總是能寫成2k+1的形式,因此可以分解為[k,k+1],所以總是能分解成連續正整數序列。對於每一個偶數,均可以分解為質因數之積,即n = pow(2, i)*pow(3, j)*pow(5,k)...,如果除了i之外,j,k...均為0,那麼n = pow(2, k),對於這種數,其所有的因數均為偶數,是不存在連續子序列和為n的,具體證明請看參考資料2。因此除了2的冪之外,所有的正整數n >=3均可以寫成一個連續的自然數之和。
另外一種解法
何海濤先生的部落格上有另外一種解法,參考如下:
用兩個數small和big分別表示序列的最小值和最大值。首先把small初始化為1,big初始化為2。如果從small到big的序列的和大於n的話,我們向右移動small,相當於從序列中去掉較小的數字。如果從small到big的序列的和小於n的話,我們向右移動big,相當於向序列中新增big的下一個數字。一直到small等於(1+n)/2,因為序列至少要有兩個數字。
更直白一點的理解就是先判定以數字2結束的連續序列和是否有等於n的,然後是以3結束的連續序列和是否有等於n的。
- /////////////////////////////////////////////////////////////////////////
- // Find continuous sequence, whose sum is n
- /////////////////////////////////////////////////////////////////////////
- void FindContinuousSequence(int n)
- {
- if(n < 3)
- return;
- int small = 1;
- int big = 2;
- int middle = (1 + n) / 2;
- int sum = small + big;
- while(small < middle)
- {
- // we are lucky and find the sequence
- if(sum == n)
- PrintContinuousSequence(small, big);
- // if the current sum is greater than n,
- // move small forward
- while(sum > n)
- {
- sum -= small;
- small ++;
- // we are lucky and find the sequence
- if(sum == n)
- PrintContinuousSequence(small, big);
- }
- // move big forward
- big ++;
- sum += big;
- }
- }
- /////////////////////////////////////////////////////////////////////////
- // Print continuous sequence between small and big
- /////////////////////////////////////////////////////////////////////////
- void PrintContinuousSequence(int small, int big)
- {
- for(int i = small; i <= big; ++ i)
- printf("%d ", i);
- printf("\n");
- }