Consecutive Numbers Sum
HardPrompt
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 + 3Example 2:
Input: n = 9
Output: 3
Explanation: 9 = 4 + 5 = 2 + 3 + 4Example 3:
Input: n = 15
Output: 4
Explanation: 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
Constraints:
1 <= n <= 109
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. We try every possible starting positive integer and, for each, we build a sum of consecutive integers. If the sum equals n, we count it as one way.
Algorithm
- Initialize
count = 0. - Iterate with an outer loop for
startfrom 1 ton. - Inside the outer loop, initialize
currentSum = 0. - Start an inner loop for
jfromstartton. - Add
jtocurrentSum. - If
currentSum == n, incrementcountand break the inner loop. - If
currentSum > n, break the inner loop. - Return
count.
Walkthrough
We can use two nested loops. The outer loop iterates through all possible starting numbers start from 1 up to n. The inner loop adds consecutive numbers to start, forming a currentSum.
- If
currentSumequalsn, we've found a valid sequence, so we increment our counter and break the inner loop to try the nextstart. - If
currentSumexceedsn, the current sequence is too large, so we break the inner loop and move to the nextstart. This method is very intuitive but its inefficiency makes it impractical for large values ofn.
class Solution { public int consecutiveNumbersSum(int n) { int count = 0; for (int start = 1; start <= n; start++) { long currentSum = 0; for (int j = start; j <= n; j++) { currentSum += j; if (currentSum == n) { count++; break; } if (currentSum > n) { break; } } } return count; }}Complexity
Time
O(n^2) - In the worst case, the outer loop runs `n` times, and the inner loop can also run up to `n` times, leading to a quadratic time complexity. This is too slow for `n` up to 10^9.
Space
O(1) - We only use a few variables to store the count and the current sum.
Trade-offs
Pros
Simple to understand and implement.
Cons
Extremely inefficient and will result in a 'Time Limit Exceeded' error for the given constraints.
A more efficient approach is to rephrase the problem mathematically. If n is a sum of k consecutive positive integers starting from x, we have the equation: n = x + (x+1) + ... + (x+k-1). This simplifies to n = k*x + k*(k-1)/2. We can iterate through possible lengths k and check if a valid positive integer x exists.
Algorithm
- Initialize
count = 0. - Loop for
k(the length of the sequence) starting from 1. - The loop condition can be
k * (k + 1) / 2 <= n, as this ensures the starting numberxcan be at least 1. - Inside the loop, calculate the sum of the arithmetic series part:
seriesSum = k * (k - 1) / 2. - Calculate the remaining part that would be
k*x:remainder = n - seriesSum. - If
remainder > 0andremainder % k == 0, it means a valid positive integerxexists. Incrementcount. - After the loop finishes, return
count.
Walkthrough
From the equation n = k*x + k*(k-1)/2, we can solve for x: x = (n - k*(k-1)/2) / k.
For a given length k, a valid solution exists if:
xis an integer. This means(n - k*(k-1)/2)must be divisible byk.xis positive. This meansn - k*(k-1)/2 > 0, which impliesn > k*(k-1)/2. This also gives us an upper bound fork. Sincek*(k-1)/2is roughlyk^2/2,kcan go up to approximatelysqrt(2n).
The algorithm iterates k from 1 upwards as long as k*(k+1)/2 <= n. For each k, it checks if (n - k*(k-1)/2) is divisible by k. If it is, we've found a valid way.
class Solution { public int consecutiveNumbersSum(int n) { int count = 0; // k is the number of terms in the series for (long k = 1; k * (k + 1) / 2 <= n; k++) { // From n = x*k + k*(k-1)/2, we get x*k = n - k*(k-1)/2. // We need to check if (n - k*(k-1)/2) is a positive multiple of k. // The loop condition k*(k+1)/2 <= n ensures x >= 1. if ((n - k * (k - 1) / 2) % k == 0) { count++; } } return count; }}Complexity
Time
O(sqrt(n)) - The loop for `k` runs as long as `k^2` is approximately less than or equal to `2n`. Thus, `k` goes up to `sqrt(2n)`, making the complexity O(sqrt(n)). This is efficient enough for the given constraints.
Space
O(1) - We only use a few variables for the loop and calculation.
Trade-offs
Pros
Much more efficient than the brute-force approach.
Passes the time limits for the given constraints.
Cons
Can be slightly less performant than the number theory approach for certain inputs (e.g., when n has many factors of 2).
This is the most optimal approach, based on a number theory insight. The problem of finding the number of ways to write n as a sum of consecutive integers is equivalent to finding the number of odd divisors of n.
Algorithm
- First, find the largest odd divisor of
n. Keep dividingnby 2 until it becomes odd. - Let the resulting odd number be
m. - Now, find the number of divisors of
m. Initializeresult = 1. - Iterate through odd numbers
dfrom 3 up tosqrt(m). - If
ddividesm:- Count how many times
dis a factor ofm. Let this beexponent. - Update
mby dividing it bydrepeatedly:m = m / d. - Update the result:
result = result * (exponent + 1).
- Count how many times
- After the loop, if
m > 1, it means the remainingmis a prime factor. Multiplyresultby 2. - Return
result.
Walkthrough
Starting from the equation n = k*x + k*(k-1)/2, we can rearrange it to 2n = k(2x + k - 1).
Let A = k and B = 2x + k - 1. We are looking for pairs of factors (A, B) of 2n.
Notice that B - A = (2x + k - 1) - k = 2x - 1, which is always an odd number. This implies that one of A and B must be odd, and the other must be even.
Let the prime factorization of n be n = 2^p * m, where m is an odd number. Then 2n = 2^(p+1) * m.
Any factor of 2n is a product of a power of 2 (from 2^(p+1)) and a factor of m. For A and B to have different parity, one must contain all the factors of 2, i.e., 2^(p+1), and the other must be purely odd.
This means that for every odd divisor d of n, we can form a pair of factors of 2n with different parity. This pair corresponds to a unique valid solution for x and k. Therefore, the number of ways is simply the number of odd divisors of n, which is the same as the number of divisors of its largest odd part, m.
The algorithm is to first find m by dividing n by 2 until it's odd, and then count the divisors of m.
class Solution { public int consecutiveNumbersSum(int n) { // The problem is equivalent to finding the number of odd divisors of n. // Step 1: Remove all factors of 2 from n to get its largest odd part. while ((n & 1) == 0) { // while n is even n >>= 1; // n = n / 2 } int result = 1; // Step 2: Find the number of divisors of the remaining odd number n. // We do this by finding its prime factorization: n = p1^a1 * p2^a2 * ... // The number of divisors is (a1+1)*(a2+1)*... for (int i = 3; i * i <= n; i += 2) { int count = 0; while (n % i == 0) { n /= i; count++; } result *= (count + 1); } // If n is still greater than 1, it means the remaining n is a prime factor. if (n > 1) { result *= 2; } return result; }}Complexity
Time
O(sqrt(n)) - In the worst case, `n` is a large prime or a product of large primes. The main work is the loop for prime factorization which runs up to `sqrt(m)`, where `m` is the odd part of `n`. Since `m <= n`, the complexity is bounded by O(sqrt(n)).
Space
O(1) - Constant extra space is used.
Trade-offs
Pros
The most efficient method.
Mathematically elegant.
Performs significantly better than the other O(sqrt(n)) approach when
nhas many factors of 2.
Cons
The underlying mathematical reasoning is less intuitive than the other approaches.
Solutions
Solution
class Solution {public int consecutiveNumbersSum(int n) { n <<= 1; int ans = 0; for (int k = 1; k * (k + 1) <= n; ++k) { if (n % k == 0 && (n / k + 1 - k) % 2 == 0) { ++ans; } } return ans; }}class Solution {public: int consecutiveNumbersSum(int n) { n <<= 1; int ans = 0; for (int k = 1; k * (k + 1) <= n; ++k) { if (n % k == 0 && (n / k + 1 - k) % 2 == 0) { ++ans; } } return ans; }};class Solution: def consecutiveNumbersSum(self, n: int) -> int: n <<= 1 ans, k = 0, 1 while k * (k + 1) <= n: if n % k == 0 and (n // k + 1 - k) % 2 == 0: ans += 1 k += 1 return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.