和相同的二元子数组-LeetCode
930. 和相同的二元子数组
🎯 问题描述(来源于LeetCode)
描述:
给定一个二元数组 nums(只包含 0 和 1)和一个整数 goal,统计并返回具有和 goal 的非空连续子数组的个数。
说明:
- 子数组是连续的。
1 <= nums.length <= 3 * 10^4。
示例:
- 示例 1:
1 | 输入: nums = [1,0,1,0,1], goal = 2 |
- 示例 2:
1 | 输入: nums = [0,0,0,0,0], goal = 0 |
💻 解题思路
思路:滑动窗口 + 容斥原理(基于您的代码)
算法步骤
- 定义辅助函数
getNums(k),该函数返回数组中和大于等于 k 的连续子数组个数。 - 在
getNums(k)中:- 初始化左指针
left = 0,当前窗口和pre = 0,答案ans = 0。 - 遍历右指针
right,将nums[right]加入pre。 - 当
pre >= k时,不断移动左指针(并将移出的元素从pre中减去),直到pre < k。 - 此时,对于当前右端点
right,所有左端点 小于left的子数组(即从0到left-1开始的子数组)的和都满足>= k。因此,共有left个以当前right为结尾的合法子数组,将left累加到ans。
- 初始化左指针
- 利用容斥原理:
sum == goal的数量 =sum >= goal的数量 -sum >= goal+1的数量。因此返回getNums(goal) - getNums(goal+1)。
代码实现(您的代码)
1 | from typing import List |
📊 性能分析
- 时间复杂度:,每个元素最多被左右指针各访问一次(两次遍历,常数倍)。
- 空间复杂度:,仅使用常数个变量。
思考
解法非常精妙!
- 传统的滑动窗口通常直接统计“和小于 k”或“和不超过 k”的子数组个数。而您的
getNums反其道而行之,通过while pre >= k收缩窗口,巧妙地统计了“和大于等于 k”的子数组个数。 - 关键在于
ans += left:当窗口和小于k时,left之前的每一个位置作为起点,与当前right组成的子数组,其和都必然大于等于k。这正是因为包含这些起点会使得窗口扩大,从而恢复>= k的状态。 - 这种写法避开了处理
0元素带来的复杂边界条件,是本题的一种优雅且高效的解法。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






