算法题:和为S的连续正数序列

    科技2024-12-02  29

    和为S的连续正数序列

    题目描述解法一思路 解法二思路

    题目描述

    小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

    解法一

    时间O(n),空间O(1)

    思路

    用数学的解法。 对于给定的一个数 S S S来说,若一个数列的和为 S S S,若使用 n n n表示数列中的第一个数,那 S S S一定满足这个式子。

    S = ( n + 0 ) + ( n + 1 ) + . . . + ( n + m ) S=(n+0)+(n+1)+...+(n+m) S=(n+0)+(n+1)+...+(n+m)

    其中 ( n + m ) (n+m) (n+m)表示连续数组中最后一个数。 那么我们将上述式子整理一下 S = ( m + 1 ) ∗ n + 1 + 2 + . . . + m = ( m + 1 ) ∗ n + m ∗ ( m + 1 ) / 2 S=(m+1)*n+1+2+...+m =(m+1)*n+m*(m+1)/2 S=(m+1)n+1+2+...+m=(m+1)n+m(m+1)/2 n = ( S − m ∗ ( m + 1 ) / 2 ) / ( m + 1 ) n=(S-m*(m+1)/2)/(m+1) n=(Sm(m+1)/2)/(m+1) 通过题意我们可以知道确定 m m m的最大值不会超过 S / 2 S/2 S/2,(若 m m m超过 S / 2 S/2 S/2,那么数组之和必定超过 S S S)。 那么通过一个 1 − S / 2 1-S/2 1S/2遍历,若计算出 n n n为整数,则表示存在一个数组。

    import java.util.ArrayList; import java.util.Comparator; public class Solution { public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { double n; ArrayList<ArrayList<Integer>> result = new ArrayList<>(); for(int m=1; m<=sum/2; m++){ n = (sum - m*(m + 1)/2)/(m+1.0); if(n > 0 && (int) n == n){ ArrayList<Integer> list = new ArrayList<>(); for(int i=0; i<=m; i++){ list.add((int)n + i); } result.add(list); } } result.sort(new Comparator<ArrayList<Integer>>() { @Override public int compare(ArrayList<Integer> list, ArrayList<Integer> list1) { if(list.get(0) > list1.get(0)){ return 1; } else if(list.get(0) < list1.get(0)){ return -1; } return 0; } }); return result; } }

    解法二

    时间O(n),空间O(1)

    思路

    滑动窗口算法,初始化窗口左指针 l e f t left left和右指针 r i g h t right right指到1处( s u m sum sum不会为0) 判断当前指针之内的元素之和 c o u n t count count(闭区间)是否为 s u m sum sum,如果和小于 s u m sum sum,则右指针向右移动一格。若 c o u n t count count大于 s u m sum sum,则左指针向右移动一格。若 c o u n t count count等于 s u m sum sum将左右指针之间的数放入数组,并将左指针加一。 循环直到左指针走过 s u m sum sum的一半(若左指针超过 s u m sum sum的一半,那 c o u n t count count的值必将大于 s u m sum sum)

    import java.util.ArrayList; public class Solution { public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) { //初始化 int count = 1; int i = 1, j = 1; ArrayList<ArrayList<Integer> > result = new ArrayList<>(); while(i <= sum/2){ if(count == sum){ //如果窗口之和等于sum的值 ArrayList<Integer> list = new ArrayList<>(); for(int k=i; k<=j; k++){ list.add(k); } result.add(list); count -= i; i++; } else if(count < sum){ //若窗口之和小于sum值 j++;//右指针向右移 count += j;//count值改变 } else{ //若窗口之和大于sum值 count -= i;//count值改变 i++;//左指针向左移 } } return result; } }
    Processed: 0.012, SQL: 8