持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
题目
给定一个正整数 n,返回 连续正整数满足所有数字之和为 n 的组数 。
示例 1:
输入: n = 5
输出: 2
解释: 5 = 2 + 3,共有两组连续整数([5],[2,3])求和后为 5。
示例 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
思考
本题难度困难。
首先是读懂题意。给定一个正整数 n,我们返回连续正整数满足所有数字之和为 n 的组数。 需要注意的是这里是连续正整数,且正整数 n 本身就是符合要求的一个答案。
我们试着分析题目。对于连续正整数,符合等差数列的定义,假设首项为 a,项数为 k,和为 n,那么
(a + a + k - 1) * k / 2 = n => (2a + k - 1) * k = 2n (1)
2a = 2n / k - k + 1 >= 2 ==> 2n / k >= k + 1 ==> 2n / k > k (2)
由(1)和(2)可知,k 是 2n 的约数,并且为较小的约数。
因此我们可以在范围内枚举 k,如果 k 为 2n 约数,并且结合 (1) ,说明找到了一组合法的 (a, k),对答案进行累加。
解答
方法一:
/**
* @param {number} n
* @return {number}
*/
var consecutiveNumbersSum = function(n) {
let ans = 0
n *= 2 // n为2n
// 在 [1, (2n)^1/2) 范围内枚举 k
for (let k = 1; k * k < n; k++) {
// k 是 2n 的约数,并且为较小的约数
if (n % k !== 0) {
continue
}
// 判断条件
if ((n / k - k + 1) % 2 === 0) {
ans++
}
}
return ans
}
// 执行用时:52 ms, 在所有 JavaScript 提交中击败了98.00%的用户
// 内存消耗:40.9 MB, 在所有 JavaScript 提交中击败了82.00%的用户
// 通过测试用例:170 / 170
复杂度分析:
- 时间复杂度:
- 空间复杂度:O(1)。