LeetCode Everyday - 和相同的二元子数组

111 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

和相同的二元子数组

给你一个二元数组 nums ,和一个整数 goal ,请你统计并返回有多少个和为 goal 的 非空 子数组。

子数组 是数组的一段连续部分。

示例1:

输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:
有 4 个满足题目要求的子数组:[1,0,1]、[1,0,1,0]、[0,1,0,1]、[1,0,1]

示例2:

输入: nums = [0,0,0,0,0], goal = 0
输出: 15

提示:

  • 1 <= nums.length <= 3 * 104
  • nums[i] 不是 0 就是 1
  • 0 <= goal <= nums.length

解题思路:

  1. 使用滑动窗口找出符合条件的最大窗口 -- 固定 l,移动 r,当 sum > S 的时候再移动 l ,最后得到在当前 r 固定下符合条件的最大窗口 [l,r]
  2. 从 l 中分出一个临时指针 tempL,向右收缩找出所有[l,r] 中符合条件的子窗口
  3. r 指针继续移动,寻找下一个相对最大的窗口 [l,r]

我的答案:

/**
 * @分析
 * 1. 构建一个滑窗,然后满足和为 S
 * 2. 滑窗向右扩展,只有当值大于 S,开始收缩 left,得到一个最大的符合条件的窗口
 * 3. 当符合条件的时候 [l,r] 中最少已经有一个状态是符合的了,现在固定 r 指针,从 l 中另外分出一个指针,来循环判定
 * 4. 之所以不直接用 l 收缩,是为了保证在 [l, r] 要保证最多,l一旦移动了,后面 r 继续移动的时候, l 就无法会到原来的位置,就会漏掉一些情况了
 */
 var numSubarraysWithSum = function (A, S) {
    let len = A.length
    let res = 0
    let sum = 0
    let l = r = 0
    while (r < len) {
        sum += A[r]
        // 只有当 sum > S 的时候,才会收缩 l 指针
        while (sum > S) {
            sum -= A[l]
            l++
        }
        // 当条件符合的时候 -- 这里是重点
        if (sum === S) {
            let tempL = l,tempSum = sum
            while(tempL<=r){
                if(tempSum === S) res++
                tempSum-=A[tempL]
                tempL++
            }
        }
        r++
    }
    return res
};

最后

如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )