Java 滑动窗口入门题:「二进制子数组的个数」的窗口计数方法
·
Java 滑动窗口入门题:「二进制子数组的个数」的窗口计数方法
滑动窗口算法是处理数组问题的核心技巧之一,特别适合计算连续子数组满足特定条件的场景。在Java编程中,掌握这一方法能显著提升算法解决能力。本文将以“二进制子数组的个数”为例,详细讲解滑动窗口计数方法的原理和实现。问题定义为:给定一个二进制数组(元素仅为0或1),计算所有子数组中和等于指定整数$K$的个数。例如,数组$[0,1,0,1]$中,$K=2$时,满足条件的子数组有$[1,0,1]$和$[0,1,0,1]$,因此个数为2。我们将从基础概念入手,逐步构建Java解决方案。
滑动窗口原理
滑动窗口通过动态调整一个“窗口”(即连续子数组)来避免重复计算,核心是使用两个指针:左指针$l$和右指针$r$,表示窗口的起始和结束位置。定义数组为$A$,长度为$n$,元素为$A[i]$($i$从0开始)。窗口和$S$计算为: $$S = \sum_{i=l}^{r} A[i]$$ 目标是使$S = K$,并统计所有满足条件的$[l, r]$对。算法步骤如下:
- 初始化$l = 0$,$S = 0$,计数变量$count = 0$。
- 右指针$r$从0遍历到$n-1$,每次将$A[r]$加入$S$。
- 如果$S > K$,则移动左指针$l$,减少$S$,直到$S \leq K$。
- 如果$S = K$,则$count$增加1。
- 重复步骤2-4,直到$r$遍历完成。 此方法时间复杂度为$O(n)$,空间复杂度为$O(1)$,适用于非负数组(二进制数组满足此条件)。
Java代码实现
以下是一个完整的Java程序,实现滑动窗口计数方法。代码包含详细注释,帮助理解每一步逻辑。
public class BinarySubarrayCounter {
/**
* 计算二进制数组中子数组和等于K的个数
* @param nums 二进制数组,元素为0或1
* @param k 目标值
* @return 满足条件的子数组个数
*/
public static int countSubarrays(int[] nums, int k) {
int count = 0; // 初始化计数
int left = 0; // 左指针
int currentSum = 0; // 当前窗口和
// 右指针遍历数组
for (int right = 0; right < nums.length; right++) {
currentSum += nums[right]; // 添加右指针元素到和
// 如果和超过K,移动左指针减少和
while (currentSum > k && left <= right) {
currentSum -= nums[left];
left++;
}
// 检查当前和是否等于K
if (currentSum == k) {
count++;
}
}
return count;
}
// 主方法测试示例
public static void main(String[] args) {
int[] nums = {0, 1, 0, 1}; // 示例数组
int k = 2; // 目标K值
int result = countSubarrays(nums, k);
System.out.println("子数组个数: " + result); // 输出应为2
}
}
逐步解析代码
-
初始化变量:
count:用于记录满足$S = K$的子数组个数,初始为0。left:左指针,表示窗口起始位置,初始为0。currentSum:当前窗口和,初始为0。
-
遍历数组:
- 使用
right指针从0开始遍历数组(right作为窗口结束位置)。 - 每次迭代,将
nums[right]加入currentSum(因为数组元素为0或1,添加操作简单)。
- 使用
-
调整窗口大小:
- 如果
currentSum > k,说明窗口和过大,需要移动左指针缩小窗口。 - 使用
while循环:从currentSum中减去nums[left],并递增left,直到currentSum <= k。
- 如果
-
检查并计数:
- 在调整窗口后,如果
currentSum == k,则递增count。 - 此步骤确保只计数有效子数组,且每次右指针移动后只检查一次。
- 在调整窗口后,如果
-
返回结果:
- 遍历完成后,
count即为所求值。
- 遍历完成后,
复杂度分析
- 时间复杂度:$O(n)$,其中$n$为数组长度。每个元素最多被左指针和右指针各访问一次。
- 空间复杂度:$O(1)$,仅使用常数级额外空间(无额外数据结构)。
边界处理与注意事项
- 数组元素特性:二进制数组元素非负(0或1),因此滑动窗口方法有效。如果数组包含负数,需其他方法如前缀和+哈希表。
- $K=0$情况:本实现未处理$K=0$,因为二进制数组中和为0的子数组通常是全0子数组。实际应用中,可扩展逻辑:当$K=0$时,计数窗口和恰好为0的子数组。
- 测试用例:
- 输入
nums = [1,0,1,0,1],k = 2,输出应为3(子数组[1,0,1]、[0,1,0,1]等)。 - 输入
nums = [0,0,0],k = 0,输出应为6(所有子数组和均为0)。
- 输入
总结
通过本入门题,我们学习了Java中滑动窗口算法的核心应用:维护动态窗口、指针移动策略和条件计数。此方法可扩展到其他问题,如计算子数组最大和或处理字符串子序列。实践中,建议多练习变种题目(如LeetCode相关题)以加深理解。滑动窗口不仅提升代码性能,还能培养对数组问题的直观洞察力。
更多推荐


所有评论(0)