原题

209. 长度最小的子数组

描述

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

  1. 示例:
  2. 输入:s = 7, nums = [2,3,1,2,4,3]
  3. 输出:2
  4. 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
  5. 进阶:
  6. 如果你已经完成了 O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
  7. 来源:力扣(LeetCode
  8. 链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
  9. 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

双指针

定义两个指针 start 和 end 分别表示子数组的开始位置和结束位置,维护变量 sum 存储子数组中的元素和(即从 nums[start] 到 nums[end] 的元素和)。
初始状态下,start 和 end 都指向下标 0,sum 的值为 0。
每一轮迭代,将 nums[end] 加到 sum,如果 sum≥s,则更新子数组的最小长度 (此时子数组的长度是 end−start+1),然后将 nums[start] 从 sum 中减去并将 start 右移,直到 sum<s,在此过程中同样更新子数组的最小长度。在每一轮迭代的最后,将 end 右移。

  1. func minSubArrayLen(s int, nums []int) int {
  2. length := len(nums)
  3. if length == 0 {
  4. return 0
  5. }
  6. ans := math.MaxInt32 // 定义结果为最大值
  7. start, end := 0, 0 // 双指针,左右边界
  8. sum := 0 // 求和,临时变量
  9. // 遍历数组
  10. for end < length {
  11. sum += nums[end]
  12. // 当 sum 大或等于目标 s 时,则更新子数组的最小长度(此时子数组的长度是 end-start+1),并减去 nums[start] ,将 start 右移
  13. for sum >= s {
  14. ans = min(ans, end-start+1)
  15. sum -= nums[start]
  16. start++
  17. }
  18. // sum 小于 s,将 end 右移
  19. end++
  20. }
  21. if ans == math.MaxInt32 {
  22. return 0
  23. }
  24. return ans
  25. }
  26. func min(a, b int) int {
  27. if a < b {
  28. return a
  29. }
  30. return b
  31. }

滑动窗口

在滑动窗口 [i,j]之间不断往后移动,如果总和小于 s,就扩大右边界 j,不断加入右边的值,直到 sum > s,之和再缩小 i 的左边界,不断缩小直到 sum < s,这时候右边界又可以往右移动。以此类推。

  1. func minSubArrayLen(s int, nums []int) int {
  2. n := len(nums)
  3. if n == 0 {
  4. return 0
  5. }
  6. left, right, res, sum := 0, -1, n+1, 0
  7. for left < n {
  8. if (right+1) < n && sum < s {
  9. right++
  10. sum += nums[right]
  11. } else {
  12. sum -= nums[left]
  13. left++
  14. }
  15. if sum >= s {
  16. res = min(res, right-left+1)
  17. }
  18. }
  19. if res == n+1 {
  20. return 0
  21. }
  22. return res
  23. }
  24. func min(a, b int) int {
  25. if a < b {
  26. return a
  27. }
  28. return b
  29. }