Given a positive integer `N`, how many ways can we write it as a sum of consecutive positive integers?
Example 1:
Input: 5
Output: 2
Explanation: 5 = 5 = 2 + 3
Example 2:
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
.
這道題給了一個正整數N,問N能寫成多少種連續正整數之和,比如9可以寫成 4+5,或者 2+3+4。這道題其實不好做,因為沒有固定的算法可以套,而更多的考察是數學知識,而且比較難想。由於要寫成連續正整數之和,則肯定是一個等差數列,並且差值為1,這個等差數列不必從1開始,假設其是從x開始的,且個數共有k個,則可以寫出這個等差數列為:
x, x+1, x+2, ..., x+k-1
其和為N,根據等差數列的求和公式,可以寫出下列等式:
kx + (k-1)k / 2 = N
變形后可得到:
kx = N - (k-1)k / 2
這樣,只要對於任意一個k值,x能得到正整數解,就表示一定會有一個對應的等差數列和為N。下面要來求k的范圍,由於k是等差數列的長度,首先肯定是要大於0的,這是下限。求上限還是要利用上面的那個式子,由於x也必須是正整數,可以得到不等式:
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)
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)