算法-双指针-和为 S 的连续正数序列

136 阅读1分钟

题目描述(剑指57.2)

输出所有和为 S 的连续正数序列。例如和为 100 的连续序列有:

[9, 10, 11, 12, 13, 14, 15, 16]
[18, 19, 20, 21, 22]。

解题思路

1、滑动窗口

滑动数组:可看成数组中框起来的一个部分。为编程方便,设置为左闭右开区间
初始值:i=1,j=1,滑动窗口位于序列最左侧,窗口大小为0。
性质窗口的左边界和右边界永远只能向右移动,而不能向左移动。

1

过程
定义:窗口内几个数和sum,左端点 i,右端点 j。 
窗口移动与结果记录:
2.1. if sum < target,sum 需要增加,即扩大窗口,右边界右移,j++; 
2.2. if sum > target,sum 需要减少,即缩小窗口,左边界右移,i++;
2.3. if sum = target,记录此时结果,即记下[i, j)的元素。这也是唯一一个i开头的序列。 接下来,左边界右移,i++;
遍历完毕,返回结果集。 

问题:窗口移动能找到全部解吗?

2

分析: 

  • (1) 1 + 2 +...+ 8 < target 

  • (2) 1 + 2 +...+ 8 + 9 > target  

  • 由(1)(2)可得,说明 1 开头的序列找不到解。

  •  (3)寻找以2开头的序列:2+...+8 < 1+2+...+8 < target. 2+3+...+8+9 ? target,如果两端相等,则记录下该序列,然后左边界右移。 结论:该2开始的序列唯一。 进一步推论,每个元素开始的序列都有判断,如果与target相等,均唯一,所以能找到全部解。

代码块

class Solution {
    public int[][] findContinuousSequence(int target) {
        int i = 1; // 滑动窗口的左边界
        int j = 1; // 滑动窗口的右边界
        int sum = 0; // 滑动窗口中数字的和
        List<int[]> res = new ArrayList<>();

        while (i <= target / 2) {
            if (sum < target) {
                // 右边界向右移动
                sum += j;
                j++;
            } else if (sum > target) {
                // 左边界向右移动
                sum -= i;
                i++;
            } else {
                // 记录结果
                int[] arr = new int[j-i];
                for (int k = i; k < j; k++) {
                    arr[k-i] = k;
                }
                res.add(arr);
                // 左边界向右移动
                sum -= i;
                i++;
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}

 

public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
    int start = 1, end = 2;
    int curSum = 3;
    while (end < sum) {
        if (curSum > sum) {
            curSum -= start;
            start++;
        } else if (curSum < sum) {
            end++;
            curSum += end;
        } else {
            ArrayList<Integer> list = new ArrayList<>();
            for (int i = start; i <= end; i++)
                list.add(i);
            ret.add(list);
            curSum -= start;
            start++;
            end++;
            curSum += end;
        }
    }
    return ret;
}

blog.csdn.net/HeavenDan/a…