题目描述

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

输出描述:

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

# -*- coding: utf-8 -*-
# @Time         : 2019-10-16 14:32
# @Author       : Jayce Wong
# @ProjectName  : job
# @FileName     : FindContinuousSequence.py
# @Blog         : https://sysujayce.github.io/
# @Github       : https://github.com/SysuJayce


class Solution:
    """
    要找连续子数组使得子数组的和为一个定值,考虑双指针标记数组的起止位置。
    具体来说,
    1. 首先将左指针指向全局数组的起点,然后移动右指针直到满足约束;
    2. 如果找到了一个满足约束的子数组,将结果保存起来之后,先将左右指针都往右移动。
       因为我们需要找另一个子数组,就需要先让当前的右指针往右移动,
       而因为右指针发生了移动,那么左指针也至少需要一次移动;
    3. 移动左指针直到找到另一个满足约束的子数组,然后重复步骤2和3。

    循环终止的条件可以是当右指针移动到了全局数组的终点,也可以是左指针超越了右指针。
    因为这样说明以该右指针为终点的子数组不存在满足约束的。
    """
    def FindContinuousSequence(self, tsum):
        left = right = 1
        res = []
        while left <= right < tsum:
            cur_sum = (left + right) * (right - left + 1) // 2
            # 局部和大于约束,需要将左指针往右,减少元素个数
            if cur_sum > tsum:
                left += 1
            # 局部和小于约束,需要将右指针往右,增加元素个数
            elif cur_sum < tsum:
                right += 1
            else:
                # 找到一个满足约束的子数组之后,将左右指针都往右移动,寻找下一个子数组
                res.append(list(range(left, right + 1)))
                right += 1
                left += 1

        return res