描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
返回值描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
示例1
输入: 9
返回值: [[2,3,4],[4,5]]
思路:
利用滑动窗口的思想,记录连续序列的左右边界以及临时序列和temp
分为三种情况
- temp > s 左边界增大
- temp < s 右边界增大
- temp == s 记录此序列并增大右边界
注意:序列至少包括两个数,所以左边界最大不超过(s+1)/2
看代码有循环嵌套,但是其实第二个for循环很少会执行,所以
时间复杂度:O(n)
空间复杂度:O(1)
代码:
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if (sum < 3) {
//和最小为3 否则不满足序列至少包括两个数的要求
return result;
}
int left = 1; //连续序列最小值
int right = 2;//连续序列最大值
int temp = 3; //临时序列和
//至少包括两个数 所以连续序列最小值必须小于(sum+1)/2
while (left < (sum+1)/2) {
if (temp > sum) {
temp -= left;
left++;
continue;
}
if (temp < sum) {
right++;
temp += right;
continue;
}
//符合题目要求 temp == sum
ArrayList<Integer> newArr = new ArrayList<>();
for (int k = left; k <= right; k++) {
newArr.add(k);
}
result.add(newArr);
right++;
temp += right;
}
return result;
}
}
增加扩展思路
参考代码
function FindContinuousSequence(sum)
{
const res = [];
if(sum <= 0) return res;
let n=2, x0, each;
while(n**2 + n <= 2*sum){
x0 = (2*sum + n - n**2) / (2*n);
if(Math.floor(x0) === x0){
each = [];
for(let i=0; i<n; ++i) each.push(x0+i);
res.push(each);
}
++n;
}
return res.sort((a, b) => a[0]-b[0]);
}