题目链接
Leetcode.829 连续整数求和 Rating : 1694
题目描述
给定一个正整数 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 < = 1 0 9 1 <= n <= 10^9 1<=n<=109
分析:等差数列
按照题意,我们要求的 n
其实是一段 d = 1
的等差数列的和。
等差数列 a n a_n an 的通项为 a n = a 1 + ( n − 1 ) ∗ d a_n = a_1 + (n-1)*d an=a1+(n−1)∗d
等差数列的求和公式为 s = ( a 1 + a n ) ∗ n 2 s = \frac{(a_1+a_n)*n}{2} s=2(a1+an)∗n
我们假设选取连续的一段 k
个元素是满足要求的,即
(
a
1
+
a
k
)
∗
k
2
=
n
\frac{(a_1+a_k)*k}{2} = n
2(a1+ak)∗k=n,这里的
a
1
a_1
a1只是我们假设的第一项。
证明:
先化简为 2 a 1 + ( k − 1 ) ∗ d = 2 n k 2a_1 + (k-1) * d = \frac{2n}{k} 2a1+(k−1)∗d=k2n
因为 d = 1
,所以
2
a
1
+
k
−
1
=
2
n
k
2a_1 + k-1 = \frac{2n}{k}
2a1+k−1=k2n,在整理一下
2
n
k
−
k
+
1
=
2
a
1
\frac{2n}{k} - k + 1 = 2a_1
k2n−k+1=2a1。
因为我们是从 1
到n
中开始选的,所以
a
1
≥
1
a_1\geq1
a1≥1,即
2
n
k
−
k
+
1
≥
2
\frac{2n}{k} - k + 1 \geq 2
k2n−k+1≥2,
2
n
k
≥
k
+
1
\frac{2n}{k} \geq k + 1
k2n≥k+1。
所以 2 n k > k \frac{2n}{k} > k k2n>k , k < 2 n k < \sqrt{2n} k<2n,最后求出了 k k k 的最大值。
因为 2 a 1 + k − 1 = 2 n k 2a_1 + k-1 = \frac{2n}{k} 2a1+k−1=k2n , 2 a 1 + k − 1 2a_1 + k-1 2a1+k−1肯定是一个正整数,所以 2 n 2n 2n 就是 k k k的倍数。
又因为
2
n
k
−
k
+
1
=
2
a
1
\frac{2n}{k} - k + 1 = 2a_1
k2n−k+1=2a1,
2
a
1
2a_1
2a1是一个偶数,所以
2
n
k
−
k
+
1
\frac{2n}{k} - k + 1
k2n−k+1 就是 2
的倍数。
所以我们最终只需要从 1 1 1 遍历到 2 n \sqrt{2n} 2n,满足这两个条件的就是一个答案。
时间复杂度: O ( n ) O(\sqrt{n}) O(n)
C++代码:
class Solution {
public:
int consecutiveNumbersSum(int n) {
int ans = 0;
for(int k = 1;k * k <= 2 * n;k++){
if((2*n) % k == 0 && ((2*n)/k - k + 1) % 2 == 0) ans++;
}
return ans;
}
};
Java代码:
class Solution {
public int consecutiveNumbersSum(int n) {
int ans = 0;
for(int k = 1;k * k <= 2 * n;k++){
if((2*n) % k == 0 && ((2*n)/k - k + 1) % 2 == 0) ans++;
}
return ans;
}
}