一、题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
二、解题思路
采用滑动窗口的思想,分为两步:
1)设定两个指针,左指针指向第一个数,右指针指向最后一个数;
2)判断两个指针之间所有数的和与目标和的大小关系,向后滑动两个指针:
如果两个指针之间所有数的和等于目标和,则把这些数都添加到一个序列中;
如果大于目标和,则说明范围太大,因此减小范围,左指针向后移动一位;
如果小于目标和,则说明范围太小,因此增大范围,右指针向后移动一位。
例如:求和为15的序列,首先两个指针指向1,2
正数序列:1,2,3,4,5,6,7
此时1~2的和为3 < 15,右指针向后移动一位到3
正数序列:1,2,3,4,5,6,7
此时1~3的和为6 < 15,右指针向后移动一位到4,10 < 15,再先后移动一位到5
正数序列:1,2,3,4,5,6,7
此时1~5的和为15 = 15,添加到一个序列,左指针向后移动一位到2
正数序列:1,2,3,4,5,6,7
此时2~5的和为14 < 15,右指针向后移动一位到6,
依次进行,直到左指针到4,右指针到6,将其添加到一个序列,而后继续指针移动…
三、编程实现
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> listAll = new ArrayList<>();
int pLow = 1, pHigh = 2;
while (pLow < pHigh) {
int currentSum = (pLow + pHigh) * (pHigh - pLow + 1) / 2;
// 当前两个指针范围内的数字和等于目标和,添加至list
if (currentSum == sum) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = pLow; i <= pHigh; i++) {
list.add(i);
}
listAll.add(list);
pLow++;
} else if (currentSum < sum) {
// 当前两个指针范围内的数字和小于目标和,右边指针向后移动,增大范围
pHigh++;
} else {
// 当前两个指针范围内的数字和大于目标和,左边指针向后移动,减小范围
pLow++;
}
}
return listAll;
}
}