Given a positive integer N
, how many ways can we write it as a sum of consecutive positive integers?html
Example 1:git
Input: 5 Output: 2 Explanation: 5 = 5 = 2 + 3
Example 2:github
Input: 9 Output: 3 Explanation: 9 = 9 = 4 + 5 = 2 + 3 + 4
Example 3:算法
Input: 15 Output: 4 Explanation: 15 = 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
Note: 1 <= N <= 10 ^ 9
.code
這道題給了一個正整數N,問N能寫成多少種連續正整數之和,好比9能夠寫成 4+5,或者 2+3+4。這道題其實很差作,由於沒有固定的算法能夠套,而更多的考察是數學知識,並且比較難想。因爲要寫成連續正整數之和,則確定是一個等差數列,而且差值爲1,這個等差數列沒必要從1開始,假設其是從x開始的,且個數共有k個,則能夠寫出這個等差數列爲:htm
x, x+1, x+2, ..., x+k-1
其和爲N,根據等差數列的求和公式,能夠寫出下列等式:blog
kx + (k-1)k / 2 = N
變形後可獲得:leetcode
kx = N - (k-1)k / 2
這樣,只要對於任意一個k值,x能獲得正整數解,就表示必定會有一個對應的等差數列和爲N。下面要來求k的範圍,因爲k是等差數列的長度,首先確定是要大於0的,這是下限。求上限仍是要利用上面的那個式子,因爲x也必須是正整數,能夠獲得不等式:get
N - (k-1)k / 2 > 0
從而獲得近似解:同步
k < sqrt(2N)
有了k的範圍就能夠開始遍歷了,首先數字N自己也是符合題意的,能夠看做是長度爲1的等差數列,則 res 能夠初始化爲1,而後i從2遍歷到 sqrt(2N),對於每一個i值,只要 (N - i(i-1)/2) 能整除i,就表示存在長度爲i的等差數列和爲N,結果 res 自增1,這樣就能夠求出全部符合題意的等差數列的個數,參見代碼以下:
解法一:
class Solution { public: int consecutiveNumbersSum(int N) { int res = 1; for (int i = 2; i < sqrt(2 * N); ++i) { if ((N - i * (i - 1) / 2) % i == 0) ++res; } return res; } };
還能夠換一種寫法,核心思路仍是跟上面的解法相同,要找是否存在和爲N的等差數列,根據上面的分析,須要看等差數列的起始值x是否爲整數,若這個等差數列每一個數字都減去一個 x-1,就變成了一個從1開始的差值爲1的等差數列,那就讓i從1開始遍歷,用一個變量 sum,每次都加上i值,這樣就至關於計算了這個等差數列的和,而後每次看 N-sum 是否能整除i,能的話就代表存在長度爲i的等差數列和爲N,參見代碼以下:
解法二:
class Solution { public: int consecutiveNumbersSum(int N) { int res = 0, sum = 0; for (int i = 1; sum < N; ++i) { sum += i; if ((N - sum) % i == 0) ++res; } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/829
參考資料:
https://leetcode.com/problems/consecutive-numbers-sum/
https://leetcode.com/problems/consecutive-numbers-sum/discuss/129227/JAVA-easy-4-lines-O(n0.5)