目录

LCR8二分查找滑动窗口

LCR8——二分查找+滑动窗口

LCR8

目录

  • 题目描述
  • 示例
  • 思路分析
  • 代码段
  • 代码逐行讲解
  • 复杂度分析
  • 总结的知识点
  • 整合
  • 总结

题目描述

给定一个正整数数组 nums 和一个整数 target,找出数组中满足其和大于等于 target 的长度最小的连续子数组,并返回其长度。如果不存在这样的子数组,则返回 0。


示例

示例 1

输入: nums = [2, 3, 1, 2, 4, 3], target = 7 输出: 2 解释:

  • 子数组 [4, 3] 的和为 7,且长度最小。

示例 2

输入: nums = [1, 4, 4], target = 4 输出: 1 解释:

  • 子数组 [4] 的和为 4,且长度最小。

示例 3

输入: nums = [1, 1, 1, 1, 1, 1, 1, 1], target = 11 输出: 0 解释:

  • 不存在满足条件的子数组。

思路分析

问题核心

我们需要找到数组中满足其和大于等于 target 的长度最小的连续子数组。

思路拆解

  1. 二分查找
  • 使用二分查找确定最小长度。
  1. 滑动窗口
  • 对于每个可能的长度,使用滑动窗口检查是否存在满足条件的子数组。

代码段

class Solution { public int minSubArrayLen(int target, int[] nums) { int sum = Arrays.stream(nums).sum(); if (sum < target) return 0; int l = 1, r = nums.length; while (l < r) { int mid = l + (r - l) / 2; if (func(target, nums, mid)) { r = mid; } else { l = mid + 1; } } return l; } private boolean func(int target, int[] nums, int mid) { int sum = 0, len = nums.length; for (int i = 0; i < mid; i++) { sum += nums[i]; if (sum >= target) return true; } for (int i = mid; i < len; i++) { sum -= nums[i - mid]; sum += nums[i]; if (sum >= target) return true; } return false; } } https://i-blog.csdnimg.cn/direct/92fbe0bb883a4db3be2c67e707ad287f.png


代码逐行讲解

  1. 计算数组总和 : int sum = Arrays.stream(nums).sum();
  • 计算数组的总和。
  1. 特殊情况处理 : if (sum < target) return 0;
  • 如果数组的总和小于 target,则返回 0。
  1. 初始化二分查找范围 : int l = 1, r = nums.length;
  • 初始化二分查找的范围为 [1, nums.length]
  1. 二分查找 : while (l < r) { int mid = l + (r - l) / 2; if (func(target, nums, mid)) { r = mid; } else { l = mid + 1; } }
  • 使用二分查找确定最小长度。
  1. 滑动窗口检查 : private boolean func(int target, int[] nums, int mid) { int sum = 0, len = nums.length; for (int i = 0; i < mid; i++) { sum += nums[i]; if (sum >= target) return true; } for (int i = mid; i < len; i++) { sum -= nums[i - mid]; sum += nums[i]; if (sum >= target) return true; } return false; }
  • 对于每个可能的长度,使用滑动窗口检查是否存在满足条件的子数组。
  1. 返回结果 : return l;
  • 返回最小长度。

复杂度分析

时间复杂度

  • 二分查找的时间复杂度为 O(log n)
  • 滑动窗口检查的时间复杂度为 O(n)
  • 因此,总时间复杂度为 O(n log n)

空间复杂度

  • 只使用了常数级别的额外空间,因此空间复杂度为 O(1)

总结的知识点

  1. 二分查找
  • 使用二分查找确定最小长度。
  1. 滑动窗口
  • 使用滑动窗口检查是否存在满足条件的子数组。
  1. 数组求和
  • 使用 Arrays.stream(nums).sum() 计算数组的总和。

整合

class Solution { public int minSubArrayLen(int target, int[] nums) { int sum = Arrays.stream(nums).sum(); if (sum < target) return 0; int l = 1, r = nums.length; while (l < r) { int mid = l + (r - l) / 2; if (func(target, nums, mid)) { r = mid; } else { l = mid + 1; } } return l; } private boolean func(int target, int[] nums, int mid) { int sum = 0, len = nums.length; for (int i = 0; i < mid; i++) { sum += nums[i]; if (sum >= target) return true; } for (int i = mid; i < len; i++) { sum -= nums[i - mid]; sum += nums[i]; if (sum >= target) return true; } return false; } }


总结

通过二分查找和滑动窗口,能够高效地找到数组中满足其和大于等于 target 的长度最小的连续子数组。