描述

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

  • 数据范围:0 < n ≤ 100
  • 进阶:时间复杂度 O(n)
  • 返回值:输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
示例
// 输入:
9
// 返回值:
[[2,3,4],[4,5]]

// 输入:
0
// 返回值:
[]
解题思路

枚举法:

  • 因为序列至少两个数,每次枚举区间的起始数字最多到目标数的一半向下取整即可,因为两个大于目标数一半的数相加一定大于目标数。
  • 第一个数从 i=1 开始,依次加上后面连续的整数,相加如果大于预期值,则说明从 i=1 开始不存在,退出,在从 i=2 开始,以此枚举,找到等于预期值的连续数后,存入二维数组,再 i++ 后继续查找

滑动窗口:

连续正数序列存在以下规律:

假设首位为 l,最后一位为 r,则 s=(l + r) * (r - l + 1) / 2

因此,可以:

  • 先定义一个两位数的区间 [1, 2]
  • 若区间所有整数和小于预期 sum,则区间向右扩大(r++)
  • 若区间所有整数和大于预期 sum,则区间向左缩小(l++)
  • 直到找出等于 sum 为止(l < r)
代码实现

枚举法:

/**
 * 枚举法
 *
 * @param sum int整型
 * @return int整型二维数组
 */
func findContinuousSequence(sum int) [][]int {
    if sum == 0 {
        return [][]int{{}}
    }

    half := math.Ceil(float64(sum) / 2)
    count := int(half)

    result := make([][]int, 0)
    for i := 1; i < count; i++ {
        tmpArr := []int{i}
        tmpSum := i
        for j := i + 1; j <= count; j++ {
            tmpArr = append(tmpArr, j)
            tmpSum += j
            if tmpSum > sum {
                break
            } else if tmpSum == sum {
                result = append(result, tmpArr)
            }
        }
    }
    return result
}

滑动窗口:

/**
 * 滑动窗口
 *
 * @param sum int 整型
 * @return int 整型二维数组
 */
func findContinuousSequence2(sum int) [][]int {
    if sum == 0 {
        return [][]int{{}}
    }

    result := make([][]int, 0)

    // 定义左右区间初始值为 1、2
    l, r := 1, 2
    for l < r {
        // 区间所有数之和
        tmpSum := (l + r) * (r - l + 1) / 2

        if tmpSum == sum {
            // 等于预期值,将区间处理成一维数组
            tmpArr := []int{}
            for i := l; i <= r; i++ {
                tmpArr = append(tmpArr, i)
            }
            result = append(result, tmpArr)

            // 移动区间左临界值,继续查找下一个
            l++
        } else if tmpSum < sum {
            // 小于预期值,左区间 l 右移一位
            r++
        } else if tmpSum > sum {
            // 大于预期值,右区间 r 左边移一位
            l++
        }
    }
    return result
}

本文由 一切随风 创作,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论