1.本题知识点
知识迁移能力
2. 题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
3. 思路
这题曾经被面试官问到过,因为之前从来没刷过算法,应试场景下后果可想而知,撕心裂肺的经历告诫我,一定要刷算法!!!
主要思路:滑动窗口和等差数列的求和公式。采用双指针,一个高位指针,一个低位指针。计算2指针之间数的和(窗口大小),通过与目标值sum的比较来改变2个指针的位置。
具体思路:
① 由于是连续正序列,所以首先设置初始指针大小1和2。然后我们就把1~2看成是一个滑动的窗口。
② 如果窗口size大于目标sum,此时我们要缩小窗口size,低位指针就往前走一步。
③ 如果窗口size小于目标sum,此时我们要放大窗口size,高位指针就往前走一步。
④ 如果窗口size等于目标sum,此时我们找到了连续序列,输出,然后低位指针往前走一步寻找下一个正确的窗口。
⑤ 终止条件为:高位指针等于sum,因为连续序列至少2个值,如果高位指针等于sum,就成了1个值的和等于sum,不符合条件。高位指针大于sum就更不合理了,所以高位指针最高能走到 sum-1处。
Java 版:
import java. util. ArrayList;
public class Solution {
private ArrayList< ArrayList< Integer> > result = new ArrayList < > ( ) ;
public ArrayList< ArrayList< Integer> > FindContinuousSequence ( int sum) {
int high = 2 , low = 1 ;
while ( high < sum) {
int curSum = ( high + low) * ( high - low + 1 ) / 2 ;
if ( curSum == sum) {
ArrayList< Integer> temp = new ArrayList < > ( ) ;
for ( int i = low; i <= high; i++ )
temp. add ( i) ;
result. add ( temp) ;
low++ ;
}
else if ( curSum < sum) {
high++ ;
}
else {
low++ ;
}
}
return result;
}
}
更简单更好理解的版本:
import java. util. ArrayList;
public class Solution {
private ArrayList< ArrayList< Integer> > result = new ArrayList < > ( ) ;
public ArrayList< ArrayList< Integer> > FindContinuousSequence ( int n) {
int start = 1 , end = 2 ;
int sum = start+ end;
while ( start < ( n+ 1 ) >> 1 )
{
if ( sum == n) {
result. add ( FinaNums ( start, end) ) ;
}
while ( sum < n) {
end++ ;
sum+= end;
if ( sum == n)
{
result. add ( FinaNums ( start, end) ) ;
}
}
sum-= start;
start++ ;
}
return result;
}
ArrayList< Integer> FinaNums ( int start, int end)
{
ArrayList< Integer> temp = new ArrayList < > ( ) ;
for ( int i = start; i<= end; i++ ) {
temp. add ( i) ;
}
return temp;
}
}