Hard
题目描述
给定一个整数 n,返回用连续的正整数表示 n 的方案数。
示例 1:
输入:n = 5
输出:2
解释:5 = 2 + 3
示例 2:
输入:n = 9
输出:3
解释:9 = 4 + 5 = 2 + 3 + 4
示例 3:
输入:n = 15
输出:4
解释:15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
提示:
- 1 <= n <= 10^9
解题思路
这是一道数学问题,关键是理解连续正整数和的数学性质。
假设我们用 k 个连续正整数表示 n,起始数为 start,那么有:
n = start + (start + 1) + ... + (start + k - 1)
n = k * start + k * (k - 1) / 2
整理得到:start = (n - k * (k - 1) / 2) / k
为了使 start 为正整数,需要满足:
n - k * (k - 1) / 2 > 0,即n > k * (k - 1) / 2(n - k * (k - 1) / 2) % k == 0
从数学角度分析,第二个条件等价于:
- 当 k 为奇数时,n 必须能被 k 整除
- 当 k 为偶数时,n 除以 k 的余数必须是 k/2
我们可以枚举所有可能的 k 值,从 1 开始直到 k * (k - 1) / 2 >= n。对于每个 k,检查是否满足上述条件。
时间复杂度优化:由于 k * (k - 1) / 2 < n,所以 k 的最大值约为 √(2n),因此算法效率很高。
代码实现
class Solution {
public:
int consecutiveNumbersSum(int n) {
int count = 0;
for (int k = 1; k * (k - 1) / 2 < n; k++) {
if (k % 2 == 1) {
if (n % k == 0) count++;
} else {
if (n % k == k / 2) count++;
}
}
return count;
}
};
class Solution:
def consecutiveNumbersSum(self, n: int) -> int:
count = 0
k = 1
while k * (k - 1) // 2 < n:
if k % 2 == 1:
if n % k == 0:
count += 1
else:
if n % k == k // 2:
count += 1
k += 1
return count
public class Solution {
public int ConsecutiveNumbersSum(int n) {
int count = 0;
for (int k = 1; k * (k - 1) / 2 < n; k++) {
if (k % 2 == 1) {
if (n % k == 0) count++;
} else {
if (n % k == k / 2) count++;
}
}
return count;
}
}
var consecutiveNumbersSum = function(n) {
let count = 0;
for (let k = 1; k * (k - 1) / 2 < n; k++) {
if ((n - k * (k - 1) / 2) % k === 0) {
count++;
}
}
return count;
};
复杂度分析
| 复杂度 | 大小 |
|---|---|
| 时间复杂度 | O(√n) |
| 空间复杂度 | O(1) |