题目
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
输入
9
返回值
[[2,3,4],[4,5]]
实现方案
1.三层循环实现
子数组的开始项和结束项分别循环一次,找到所有可能的组合,再用第三层循环累加计算和与S作比较。
function createArray(i, j) {
const arr = [];
for (let k = i; k <= j; k++) {
arr.push(k);
}
return arr;
}
function getContinuousSubstring(count) {
const result = [];
const middleValue = Math.floor(count / 2);
for (let i = 1; i <= middleValue; i++) {
for (let j = i + 1; j < count; j++) {
let sum = 0;
for (let k = i; k <= j; k++) {
sum += k;
}
if (sum === count) {
//找到了
result.push(createArray(i, j))
}
}
}
return result;
}
// 验证
console.log('和为15');
console.log(getContinuousSubstring(15));
console.log('和为9');
console.log(getContinuousSubstring(9));
console.log('和为200');
console.log(getContinuousSubstring(200));
验证效果
2.两层循环+等差数列求和公式
和上面的实现方案一样,两层循环用来找到所有开始项和结束项的组合情况,这次不一样的地方是计算子串和的时候不用再遍历一次,直接使用等差数列的求和公式就可以啦。
子串和 = ( (开始项 + 结尾项) / 2 ) * (结尾项 - 开始项 + 1)
function createArray(i, j) {
const arr = [];
for (let k = i; k <= j; k++) {
arr.push(k);
}
return arr;
}
function getContinuousSubstring(count) {
const result = [];
const middleValue = Math.floor(count / 2);
for (let i = 1; i <= middleValue; i++) {
for (let j = i + 1; j < count; j++) {
const sum = ((i + j) / 2) * (j - i + 1)
if (sum === count) {
//找到了
result.push(createArray(i, j))
}
}
}
return result;
}
// 验证
console.log('和为15');
console.log(getContinuousSubstring(15));
console.log('和为9');
console.log(getContinuousSubstring(9));
console.log('和为200');
console.log(getContinuousSubstring(200));
验证效果:
3.滑动窗口
滑动窗口设计满足如下这几个原则:
1.用left 和 right 标记窗口的开始项和结尾项;两个都只会右移,如果子串和大于S,则右移left,如果子串和小于S则右移right.
2.如果子串和等于S说明找到了其中一个子串,添加到结果数组中后,将left或right右移一位。
3.刚开始left right都在最左边,继续上面的操作,直到left已经不小于中间项才跳出。
function createArray(i, j) {
const arr = [];
for (let k = i; k <= j; k++) {
arr.push(k);
}
return arr;
}
function getContinuousSubstring(count) {
let left = 1;
let right = 1;
const result = [];
while (left <= Math.floor((count / 2))) {
const sum = ((left + right) / 2) * (right - left + 1);
if (sum > count) {
left++;
} else if (sum < count) {
right++;
} else {
result.push(createArray(left, right));
left++;
}
}
return result;
}
// 验证
console.log('和为15');
console.log(getContinuousSubstring(15));
console.log('和为9');
console.log(getContinuousSubstring(9));
console.log('和为200');
console.log(getContinuousSubstring(200));
验证效果
这应该是最好方案,找到窗口的时间复杂度为: O(n)
总结
本文总结了输出所有和为S的连续正数序列的三种实现方案:三层循环,两层循环+等差求和,滑动窗口等。希望能对你有所帮助。