和为S的连续正数序列

来源:互联网 发布:网络谣言研究报告 编辑:程序博客网 时间:2024/05/19 08:00

题目描述:

现在要求有多少种连续的正数序列的和为100(至少包括两个数)。其中一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? 

思路:

由于题目要求至少包含两个数,那么所有可能的序列的最大值均不会超过(sum + 1) >> 1;1, 2, start-1, start, start+1, start+2, ..., end-1 , end.于是,从 end= (sum + 1)>> 1, start = end - 1 开始求和。while( start > 0){    tmp += start;    if(tmp == sum)        将 start, ..., end记录下来;        tmp -= end;        end--;        start--;    else if(tmp < sum)        start--;    else //tmp > sum        tmp -= end;        end--;        start--;    //每比较一次,需要更新start,end,tmp的值}时间复杂度为O(start) = O(sum)

代码实现如下:

import java.util.ArrayList;public class SequenceSum {    public static void main(String[] args) {        int target = 9;        for (ArrayList<Integer> list : findSequence(target)) {            for (int x : list)                System.out.print(x + " ");            System.out.println("");        }    }    private static ArrayList<ArrayList<Integer>> findSequence(int sum) {        if (sum <= 2)            return new ArrayList<>();        int end = (sum + 1) >> 1, start = end - 1, tmp = end;        ArrayList<ArrayList<Integer>> aal = new ArrayList<>();        while (start > 0) {            tmp += start;            if (tmp == sum) {                ArrayList<Integer> al = new ArrayList<>();                for (int i = start; i <= end; i++) {                    al.add(i);                }                aal.add(al);                tmp -= end;                end--;            } else if (tmp > sum) {                tmp -= end;                end--;            }            start--;    }}

输出如下:

4 5 2 3 4 

也可以根据序列start从小到大输出序列
aal.add(0,al);
但是由于ArrayList是基于数组实现的,每次调用add(0,al)必然导致0以后的所有值需要后移一位,效率低下。可以将ArrayList换成LinkedList,这样效率会高一些,特别是链表较长时,效率会更高。