Skip to main content

0829 - Consecutive Numbers Sum (Hard)

https://leetcode.com/problems/consecutive-numbers-sum/

Problem Statement

Given an integer n, return the number of ways you can write n as the sum of consecutive positive integers.

Example 1:

Input: n = 5
Output: 2
Explanation: 5 = 2 + 3

Example 2:

Input: n = 9
Output: 3
Explanation: 9 = 4 + 5 = 2 + 3 + 4

Example 3:

Input: n = 15
Output: 4
Explanation: 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5

Constraints:

  • 1 <= n <= 10^9

Approach: Math

The first observation is that nnitself is one of the answer. We can define ans=1ans = 1.

Let xx be the first number of the sequence, then we should have

n=x+(x+1)+(x+2)+...+(x+(k1))n = x + (x + 1) + (x + 2) + ... + (x + (k - 1))

We can arrange the formula. First there are kk terms of xx so we can just multiply them together. The remaining sum is just 0+1+2+...+(k1)0 + 1 + 2 + ... + (k - 1) which is k(k1)/2k * (k - 1) / 2. Why? We can get that from sum of nn terms in Arithmetic Progress (A.P.) formula

S=(n/2)(2a+(n1)d)S = (n / 2) * (2 * a + (n - 1) * d)

where aais the first term and dd is the common difference.

We can further transform from

S=(n/2)(a+a+(n1)d)S = (n / 2) * (a + a + (n - 1) * d)

to the following expression

S=(n/2)(al)S = (n / 2) * (a * l)

where llis the last term and it is equivalent to a+(n1)da + (n - 1) * d.

Back to our problem, from 0+1+2+...+(k1)0 + 1 + 2 + ... + (k - 1), we can see that the first term is 0 and and last term is (k1)(k - 1). Therefore, we can know that 0+1+2+...+(k1)=(k/2)(0+(k1))=k(k1)/20 + 1 + 2 + ... + (k - 1) = (k / 2) * (0 + (k - 1)) = k * (k - 1) / 2.

Now we have kx=nk(k1)/2k * x = n - k * (k - 1) / 2, which means we can construct a sum of nnusing kkterms starting from xx if nk(k1)/2n - k * (k - 1) / 2 is a multiple of kk. We can iterate kkand check if this statement is true or not. The next problem would be "What is the range of kk?".

Since nnitself is already considered, so we need to start kk from 2. From the above formula, nk(k1)/2n - k * (k - 1) / 2 needs to be greater than 0.

nk(k1)/2>0n - k * (k - 1) / 2 > 0 k(k1)<2nk * (k - 1) < 2 * n

The upper bound for kk approximately would be around 2n+k\sqrt {2 * n + k}. Therefore, we iterate kk from 22 to 2n+k\sqrt {2 * n + k} to check if nk(k1)/2n - k * (k - 1) / 2 is a multiple of kk. If so, it means we have one sequence so we increase the answer by 11.

Written by @wingkwong
class Solution {
public:
int consecutiveNumbersSum(int n) {
int ans = 1;
// n = x + (x + 1) + (x + 2) + ... + (x + (k - 1))
// n = k * x + k * (k - 1) / 2
// k * x = n - k * (k - 1) / 2
// n - k * (k - 1) / 2 > 0
// k * (k - 1) < 2 * n
// ~= k * k < 2 * n + k
for (int k = 2; k < sqrt(2 * n + k); k++) {
ans += (n - (k * (k - 1) / 2)) % k == 0;
}
return ans;
}
};