「这是我参与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^4nums[i]is either0or1.0 <= goal <= nums.length
题目大意
给定一个二元数组 nums ,和一个整数 goal ,求有多少个和为 goal 的 非空 子数组。
解题思路
方法1:前缀和 + 哈希表
- 对于连续子数组的和可以使用前缀和进行计算
- 在遍历数组的过程中,用哈希表记录前缀和的数量,则遍历到
i时,只需查找哈希表中sum = preSum[i] - goal的数量 - 特别地,初始化设
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
};
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
方法2:滑动窗口
考虑到数组中只有0和1,对于满足条件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
};
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(1)