剑指 Offer 57 - II. 和为s的连续正数序列 - 力扣(LeetCode) (leetcode-cn.com)
目录
解法1:数学手段
运行结果
分析
确定可能的元素个数
根据等差数列所有项之和与项数的关系来筛选
代码
解法2:滑动窗口
运行结果
分析
代码
满足条件的序列最少要有两个元素,最多可能有几个元素?
如果n个连续正数之和为s,设第一个数为x,即:
x, x + 1, ..., x + n-1
这个序列之和:n * x + n * (n - 1) / 2 == s
我们需要求的是n的最大值,那么x需要取得最小值,x至少是1,所以令x = 1代入上式,得到:
n * (n + 1) == 2 * s
又因为:n ^ 2 < n * (n + 1) == 2 * s
所以:n < sqrt ( 2 * s )
则满足要求的序列至多有sqrt ( 2 * s )个元素,我们记为N
对于任意n ∈ [ 2, N ]个连续正数组成的,和为s的序列,其平均值为 s / n,第一个元素:
x = s / n - (n-1) / 2 (可以验证:x * n + n * (n - 1)/ 2 == s)
如果n为奇数,那么均值s / n必然为该序列的中值,且n必然整除s,即:
s % n == 0
如果n为偶数,那么均值s / n必然为该序列中间两个数的均值
设中间两个数为a, a+1
则:
s / n = (a + a+1) / 2
s / n = a + 1/2
s = a * n + n / 2
所以:s % n == n / 2
class Solution {
public:
bool check(int s, int n) {
return ((n & 1) && !(s % n)) ||
(!(n & 1) && (s % n == n / 2));
}
vector> findContinuousSequence(int s) {
int N = sqrt(2 * s);
vector> res;
for (int i = N; i >= 2; --i) {
if (check(s, i)) {
int a1 = s / i - (i - 1) / 2;
vector arr(i);
for (int j = 0; j < i; ++j) {
arr[j] = a1 + j;
}
res.push_back(arr);
}
}
return res;
}
};
我们考虑检查所有可能的连续整数序列:
从1开始的连续整数序列,从2开始的连续整数序列,……,从s/2开始的连续整数序列
由于这些序列之间存在大量重复的元素,我们希望通过找出他们之间的关系来避免重复的求和运算。
设f(i)表示从i开始的、和小于s的连续整数序列的最后一项,s[i, f(i)]表示这个闭区间上所有整数之和。
则有:
s[i, f(i)] = i + i+1 + ... + f(i) < s
s[i, f(i)+1] = i + i+1 + ... + f(i) + f(i)+1 >= s
同理:
s[i+1, f(i+1)] = i+1 + i+2 + ... + f(i+1) < s
s[i+1, f(i+1)+1] = i+1 + i+2 + ... + f(i+1) + f(i+1)+1 >= s
由此我们可以找出f(i+1)与f(i)的关系:
由 s[i+1, f(i)] < s[i, f(i)] < s
得:
f(i+1) >= f(i)
由
s[i+1, f(i)+2] = s[i, f(i)+1] + f(i)+2 - i
s[i, f(i)+1] >= s
f(i)+2 - i > 0
得:
s[i+1, f(i)+2] >= s
则: f(i+1)+1 <= f(i)+2
即: f(i+1) <= f(i)+1
根据以上关系,我们得到:
f(i) <= f(i+1) <= f(i) + 1 <= f(i+1) + 1
因此当检验完s[i, f(i)+1]之后,我们只需检验s[i+1, f(i)+1],用s[i, f(i)+1] - i 即可。
class Solution {
public:
vector> findContinuousSequence(int s) {
vector> res;
int end = 1;
int sum = 1;
for (int beg = 1; beg <= s / 2; ++beg) {
while (sum < s) {
++end;
sum += end;
}
if (sum == s) {
int size = end - beg + 1;
vector arr(size);
for (int i = 0; i != size; ++i) arr[i] = beg + i;
res.push_back(arr);
}
sum -= beg;
}
return res;
}
};