為了找份暑期實習生的工作,今天去某公司面試。很喜歡這樣的公司,首先不問出身、不問愛好,直接給你一台電腦,幾道編程題目,讓你寫程序。
其中有道題目是將一個整數分解為連續正整數之和,如15可以分解為:
15 = 1 + 2 + 3 + 4 + 5
15 = 4 + 5 + 6
15 = 7 + 8
這道題,我用最死板的方法給編出來了。輸入數n,設置起始位置i,再遍歷連續正整數的長度k,由公式計算出 sum = i + (i+1) + ... + (i+k) = (k+1) * (2*i + k) / 2,判斷與n的關系,若相等則打印出從i到i+k這(k+1)個數;若sum>n,則break;
偽碼如下:
for (i = 1; i <= n/2; i++) for (k = 1; ; k++) sum = (k+1) * (2*i + k) / 2; if (sum > n) break; if (sum == n) print (從i到i+k的值)
但這算法的復雜度高呀!達到O(n2)!肯定不是最好的方法,回來我在網上找了一下這個題目,發現有很多解法,說一個比較容易理解的吧。
我們計算從i開始連續k個數之和的計算公式如下:
sum = k * (2 * i + k - 1) / 2;
現在題目要求sum == n 的所有可能情況,上面的解法是從起始位置開始循環,又根據連續個數循環,兩重循環,那么從上面的公式逆向想想,如果sum==n時,i與k直接滿足什么關系呢?有 k * (2 * i + k - 1) = 2 * n。那么如果用k循環,計算出起始位置 i = ( 2*n / k - k + 1) / 2,豈不是時間復雜度降到線性的了。如下:
for (k = 1; k <= n/2; k++) if (2*n % k == 0) //能被k整除 temp = 2*n / k - k + 1; if (temp % 2 == 0) //能被2整除 i = temp / 2; print (從i到i+k-1的值)
ok!