1. 程式人生 > >和為N的連續正整數序列

和為N的連續正整數序列

題目

輸入一個正整數數N,輸出所有和為N連續正整數序列。例如輸入15,由於1+2+3+4+5=4+5+6=7+8=15,所以輸出3個連續序列1-54-67-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++,繼續迴圈。

  1. bool find_sequence(
    int N)   
  2. {  
  3.     bool has = false;  
  4.     int k = 2, x, m ;  //k為連續序列的數目,x為起始的值,m用於判斷是否有滿足條件的值。
  5.     while (true) {   
  6.         x = (N - k*(k-1)/2) / k;  //求出k個連續正整數和為N的起始值x
  7.         m = (N - k*(k-1)/2) % k; //m用於判斷是否有滿足條件的連續正整數值
  8.         if (x <= 0) break;    //退出條件,如果x<=0,則迴圈退出。
  9.         if (!m) {             
    //m為0,表示找到了連續子序列和為N。
  10.             has = true;  
  11.             output(x, k);  
  12.         }  
  13.         k++;  
  14.     }  
  15.     return has;  
  16. }  
  17. void output(int x, int k)   
  18. {  
  19.     for (int i=0; i<k; i++) {  
  20.         cout << x++ << " ";  
  21.     }  
  22.     cout << endl;  
  23. }  

擴充套件

問題:是不是所有的正整數都能分解為連續正整數序列呢?

答案不是。並不是所有的正整數都能分解為連續的正整數和,如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均可以寫成一個連續的自然數之和。

另外一種解法

何海濤先生的部落格上有另外一種解法,參考如下:

用兩個數smallbig分別表示序列的最小值和最大值。首先把small初始化為1big初始化為2。如果從smallbig的序列的和大於n的話,我們向右移動small,相當於從序列中去掉較小的數字。如果從smallbig的序列的和小於n的話,我們向右移動big,相當於向序列中新增big的下一個數字。一直到small等於(1+n)/2,因為序列至少要有兩個數字。

更直白一點的理解就是先判定以數字2結束的連續序列和是否有等於n的,然後是以3結束的連續序列和是否有等於n的。

  1. /////////////////////////////////////////////////////////////////////////
  2. // Find continuous sequence, whose sum is n
  3. /////////////////////////////////////////////////////////////////////////
  4. void FindContinuousSequence(int n)  
  5. {  
  6.       if(n < 3)  
  7.             return;  
  8.       int small = 1;   
  9.       int big = 2;  
  10.       int middle = (1 + n) / 2;  
  11.       int sum = small + big;  
  12.       while(small < middle)  
  13.       {  
  14.             // we are lucky and find the sequence
  15.             if(sum == n)  
  16.                   PrintContinuousSequence(small, big);  
  17.             // if the current sum is greater than n, 
  18.             // move small forward
  19.             while(sum > n)  
  20.             {  
  21.                   sum -= small;  
  22.                   small ++;  
  23.                   // we are lucky and find the sequence
  24.                   if(sum == n)  
  25.                         PrintContinuousSequence(small, big);  
  26.             }  
  27.             // move big forward
  28.             big ++;  
  29.             sum += big;  
  30.       }  
  31. }  
  32. /////////////////////////////////////////////////////////////////////////
  33. // Print continuous sequence between small and big
  34. /////////////////////////////////////////////////////////////////////////
  35. void PrintContinuousSequence(int small, int big)  
  36. {  
  37.       for(int i = small; i <= big; ++ i)  
  38.             printf("%d ", i);  
  39.       printf("\n");  
  40. }  

參考資料