剑指 Offer 57 - II. 和为s的连续正数序列

77 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

Leetcode : leetcode-cn.com/problems/he…

GitHub : github.com/nateshao/le…

剑指 Offer 57 - II. 和为s的连续正数序列

题目描述 :输入一个正整数 target,输出所有和为 target的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

难度:简单

示例 1:

 输入:target = 9
 输出:[[2,3,4],[4,5]]

示例 2:

 输入:target = 15
 输出:[[1,2,3,4,5],[4,5,6],[7,8]]

Go

image.png

func findContinuousSequence(target int) [][]int {
   left := 1
   right := 2
   var res [][]int
   for left < right {
      sum := (left + right) * (right - left + 1) / 2
      if sum == target {
         var list []int
         for i := left; i <= right; i++ {
            list = append(list, i)
         }
         res = append(res, list)
         left++
      } else if sum < target {
         right++
      } else {
         left++
      }
   }
   return res
}

方法:滑动窗口(双指针)

当窗口的和小于 target 的时候,窗口的和需要增加,所以要扩大窗口,窗口的右边界向右移动

当窗口的和大于 target 的时候,窗口的和需要减少,所以要缩小窗口,窗口的左边界向右移动

当窗口的和恰好等于 target 的时候,我们需要记录此时的结果。设此时的窗口为 [i, j), 那么我们已经找到了一个 i 开头的序列,也是唯一一个 i 开头的序列,接下来需要找 i+1 开头的序列,所以窗口的左边界要向右移动


设连续正整数序列的左边界 i 和右边界 j ,则可构建滑动窗口从左向右滑动。循环中,每轮判断滑动窗口内

元愫和与目标值 target 的大小关系,若相等则记录结果,若大于 target 则移动左边界 i (以减小窗口内的元 素和),若于 target 则移动右边界 j (以增大窗口内的元素和) 。

算法流程:

  1. 初始化:左边界 i = 1,右边界 j = 2,元素和 s = 3,结果列表 res ;

  2. 循环:

    • 当 i ≥ j时跳出;
    • 当s > target时:向右移动左边界 i = i + 1 ,并更新元素和 s ;
    • 当s < target时:向右移动右边界 j = j + 1,并便新元索和 s ;
    • 当s = target时:记绿连续整数序列,饷右移动左边界 i = i + 1 ;
  3. 返回值:返回结果列表 res ;

复杂度分析;

  • 时间复杂度:由于两个指针移动均单调不减,且最多移动| target / 2 | 次,即方法一提到的枚举的上界,所 以时间复杂度为 O(target) 。
  • 空间复杂度:O(1) ,除了答案数组织需要常数的空间存放若干变量。
 package com.nateshao.sword_offer.topic_44_findContinuousSequence;
 ​
 import java.util.ArrayList;
 import java.util.List;
 ​
 /**
  * @date Created by 邵桐杰 on 2022/1/25 15:37
  * @微信公众号 千羽的编程时光
  * @个人网站 www.nateshao.cn
  * @博客 https://nateshao.gitee.io
  * @GitHub https://github.com/nateshao
  * @Gitee https://gitee.com/nateshao
  * Description:
  */
 public class Solution {
     public static void main(String[] args) {
         int[][] findContinuousSequence = findContinuousSequence(9);
         for (int[] ints : findContinuousSequence) {
             for (int anInt : ints) {
                 System.out.println("anInt = " + anInt);
             }
         }
     }
 ​
     /**
      * 解法:滑动窗口(双指针)
      * @param target
      * @return
      */
     public static int[][] findContinuousSequence(int target) {
         int i = 1, j = 2, s = 3;
         List<int[]> res = new ArrayList<>();
         while (i < j) {
             if (s == target) {
                 int[] ans = new int[j - i + 1];
                 for (int k = i; k <= j; k++)
                     ans[k - i] = k;
                 res.add(ans);
             }
             if (s >= target) {
                 s -= i;
                 i++;
             } else {
                 j++;
                 s += j;
             }
         }
         return res.toArray(new int[0][]);
     }
 ​
 }

参考链接:leetcode-cn.com/problems/he…

\