LeetCode——930 BinarySubarraysWithSum

397 阅读1分钟

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

930.BinarySubarraysWithSum

题目

Given a binary array nums and an integer goal, return the number of non-empty subarrays with a sum goal.

A subarray is a contiguous part of the array.

Example 1:

Input: nums = [1,0,1,0,1], goal = 2
Output: 4
Explanation: The 4 subarrays are bolded and underlined below:
[<u>1,0,1</u>,0,1]
[<u>1,0,1,0</u>,1]
[1,<u>0,1,0,1</u>]
[1,0,<u>1,0,1</u>]

Example 2:

Input: nums = [0,0,0,0,0], goal = 0
Output: 15

Constraints:

  • 1 <= nums.length <= 3 * 10^4
  • nums[i] is either 0 or 1.
  • 0 <= goal <= nums.length

题目大意

给定一个二元数组 nums ,和一个整数 goal ,求有多少个和为 goal非空 子数组。

解题思路

方法1:前缀和 + 哈希表

  1. 对于连续子数组的和可以使用前缀和进行计算
  2. 在遍历数组的过程中,用哈希表记录前缀和的数量,则遍历到i时,只需查找哈希表中sum = preSum[i] - goal的数量
  3. 特别地,初始化设map.set(0, 1)

代码

/**
 * @param {number[]} nums
 * @param {number} goal
 * @return {number}
 */
var numSubarraysWithSum = function(nums, goal) {
    const n = nums.length
    const map = new Map()
    let preSum = 0
    let ret = 0
    map.set(0, 1)
    for (let i = 0; i < n; i++) {
        preSum += nums[i]
        ret += (map.get(preSum - goal) || 0)
        map.set(preSum, (map.get(preSum) || 0) + 1)
    }
    return ret
};

复杂度分析

  1. 时间复杂度:O(n)
  2. 空间复杂度:O(n)

方法2:滑动窗口

考虑到数组中只有01,对于满足条件preSum[j] - preSum[i] === goal(其中j为遍历数组当前元素)的i处于一个连续的区间中。可以维护一个滑动窗口,使得其值为goal;另外维护一个区间[left1, left2)i的值就处于这个区间中

代码

var numSubarraysWithSum = function(nums, goal) {
    const n = nums.length
    let left1 = left2 = right = 0
    let sum1 = sum2 = 0
    let ret = 0
    while (right < n) {
        sum1 += nums[right]
        while (sum1 > goal && left1 <= right) {
            sum1 -= nums[left1]
            left1++
        }
        sum2 += nums[right]
        while (sum2 >= goal && left2 <= right) {
            sum2 -= nums[left2]
            left2++
        }
        ret += (left2 - left1)
        right++
    }
    return ret
};

复杂度分析

  1. 时间复杂度:O(n)
  2. 空间复杂度:O(1)