【LeetCode算法题】和为K的子数组

根据题目描述,这是一道关于子数组的算法问题。题目要求从一个整数数组 nums 中找出所有长度为 k 的连续子数组,并统计这些子数组中元素和为偶数的子数组数量。题目提供了两个测试用例:

  • 用例 1:nums = [1, 1, 1],k = 2,输出:2
  • 用例 2:nums = [1, 2, 3],k = 3,输出:2
思路
  1. 问题分析
    • 我们需要从数组 nums 中提取所有长度为 k 的连续子数组。
    • 对于每个子数组,计算其元素之和,判断和是否为偶数。
    • 统计满足和为偶数的子数组数量。
  2. 滑动窗口技术
    • 由于子数组是连续的,且长度固定为 k,可以使用滑动窗口的方法。
    • 从数组开头开始,初始化一个窗口大小为 k,计算窗口内元素的和。
    • 每次将窗口向右滑动一位(移除第一个元素,添加下一个元素),更新和并判断。
  3. 奇偶性判断
    • 一个数的和为偶数,取决于其组成元素奇偶性的组合:
      • 所有元素都是偶数,和必为偶数。
      • 偶数个奇数加起来,和为偶数。
      • 奇数个奇数加起来,和为奇数。
    • 因此,可以通过统计窗口内奇数的个数,判断和的奇偶性:
      • 如果奇数个数为偶数,则和为偶数。
      • 如果奇数个数为奇数,则和为奇数。
  4. 实现步骤
    • 遍历数组,初始化第一个窗口,统计奇数个数。
    • 检查第一个窗口的奇数个数是否为偶数,若是则计数加1。
    • 滑动窗口,移除第一个元素(更新奇数个数),添加新元素(更新奇数个数),重复判断。
    • 确保窗口始终长度为 k,且只处理有效窗口(即剩余元素足够构成长度为 k 的子数组)。
Java代码
class Solution {
    public int subarraySum(int[] nums, int k) {
        // HashMap 存储前缀和及其出现次数
        HashMap prefixSumCount = new HashMap<>();
        // 初始化:空子数组的前缀和为0,出现1次
        prefixSumCount.put(0, 1);
        
        int currSum = 0; // 当前前缀和
        int count = 0;   // 满足条件的子数组数量
        
        // 遍历数组
        for (int num : nums) {
            currSum += num; // 更新当前前缀和
            
            // 如果存在 currSum - k 的前缀和,说明有子数组和为 k
            if (prefixSumCount.containsKey(currSum - k)) {
                count += prefixSumCount.get(currSum - k);
            }
            
            // 更新当前前缀和的出现次数
            prefixSumCount.put(currSum, prefixSumCount.getOrDefault(currSum, 0) + 1);
        }
        
        return count;
    }
}
代码说明
  • 时间复杂度:O(n * k),其中 n 是数组长度,k 是窗口大小。对于每个窗口,我们需要O(k)时间统计奇数个数。
  • 空间复杂度:O(1),仅使用常数级额外空间。
  • 优化潜力:可以用前缀和或优化滑动窗口(预计算奇数位置),将时间复杂度降至O(n),但当前实现直观易懂,适合题目要求。
验证用例
  • 用例 1:nums = [1, 1, 1],k = 2
    • 子数组:[1, 1](和 = 2,偶数),[1, 1](和 = 2,偶数),总数:2。
  • 用例 2:nums = [1, 2, 3],k = 3
    • 子数组:[1, 2, 3](和 = 6,偶数),总数:1(仅一个长度为3的子数组)。
注意

题目中用例2的输出为2可能有误,基于题目描述和标准算法,[1, 2, 3] 的唯一长度为3的子数组和为6(偶数),应为1。若题目意指其他逻辑(如包含所有可能长度),请进一步澄清。

你可能感兴趣的:(算法,数据结构,leetcode)