和为 K 的子数组-leetcode

题目描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

解法一

思路:

枚举算法,从下标i开始,统计后面所有位置的字串和,当中若出现和为k则个数加一

代码:

public class leetcode_010 {
    public static int subarraySum(int[] nums, int k) {
        int ans=0;
        int tempSum=0;
        for(int i=0;i<nums.length;i++){
            tempSum+=nums[i];
            if(tempSum==k)ans++;
            for (int j=i+1;j<nums.length;j++){
                tempSum+=nums[j];
                if(tempSum==k)ans++;
            }
            tempSum=0;
        }
        return ans;

    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] line = sc.nextLine().split(",");
        int[] nums= Arrays.stream(line).mapToInt(Integer::parseInt).toArray();
        int k = sc.nextInt();
        int res = subarraySum(nums,k);
        System.out.println(res);
    }
}

解法二

思路:

来自官方的解答,采用前缀和和哈希表进行优化,时间复杂度为O(n)。

  • 前缀和(Prefix Sum):定义 pre[i] 为数组从索引 0i 的所有元素之和。例如,对于数组 numspre[i] = nums[0] + nums[1] + ... + nums[i]
  • 子数组和:子数组 [j..i] 的和可以表示为 pre[i] - pre[j-1]。注意,当 j=0 时,pre[j-1] 定义为 0(即没有元素时的前缀和)。
  • 目标条件:我们想找到所有满足 pre[i] - pre[j-1] == k 的子数组。这等价于 pre[j-1] == pre[i] - k。因此,对于每个 i,我们需要统计有多少个 j(其中 j0i)使得 pre[j-1] 等于 pre[i] - k

为了高效地统计这些 j 的个数,我们使用一个哈希表(如 HashMap),键是前缀和的值,值是该前缀和出现的次数。这样,对于每个 i,我们可以直接在哈希表中查找 pre[i] - k 的出现次数,从而避免重复计算。

步骤详解

  1. 初始化
    • 创建一个哈希表 map,用于存储前缀和及其出现次数。
    • 初始时,放入前缀和 0,出现次数为 1。这是因为当没有元素时,前缀和为 0,且这相当于 j=0 时的 pre[j-1] = 0
    • 初始化当前前缀和 pre = 0 和计数器 count = 0
  2. 遍历数组
    • 对于每个元素 nums[i]
      • 更新当前前缀和:pre = pre + nums[i]
      • 计算目标值 target = pre - k。这个目标值就是我们要在哈希表中查找的 pre[j-1]
      • 如果 target 存在于哈希表中,则说明存在若干下标 j(对应 pre[j-1] = target),使得子数组 [j..i] 的和为 k。因此,将 count 加上 map.get(target)
      • 将当前前缀和 pre 加入哈希表:如果 pre 已存在,则将其出现次数加 1;否则,放入 pre 并设置次数为 1
  3. 返回结果
    • 遍历结束后,count 即为所有和为 k 的连续子数组的个数。

遍历的过程中,我们先求出前缀和,当下标来到i时,我们求pre[i]-k出现的次数,即需要统计有多少个 j(其中 j0i)使得 pre[j-1] 等于 pre[i] - k。这些前缀和在我们求pre[i]前就已经求出。

为什么pre[i] - k出现的次数等于多少个j,因为我们从头开始求前缀和,[0i]只会统计一次,当出现相同的前缀和时,是不用的[0i]计算得来的。

代码:

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0, pre = 0;
        HashMap < Integer, Integer > mp = new HashMap < > ();
        mp.put(0, 1);
        for (int i = 0; i < nums.length; i++) {
            pre += nums[i];
            if (mp.containsKey(pre - k)) {
                count += mp.get(pre - k);
            }
            mp.put(pre, mp.getOrDefault(pre, 0) + 1);//若当前前缀和不存在,则创建该前缀和,出现次数置为1,若出现过这个前缀和,则该前缀和出现的次数加1
        }
        return count;
    }
}
posted @ 2025-09-13 18:18  狐狸胡兔  阅读(38)  评论(0)    收藏  举报