力扣:和为K的子数组

力扣题目

560. 和为K的子数组
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :

数组的长度为 [1, 20,000]。
数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。

引入前缀和

  • 什么是前缀和:
    第 0 项当前项总和
    如果用一个数组表示:
    prefixSum[x]:nums 的 第 0 到 第 x 项 的总和

      prefixSum[x] = nums[0] + nums[1] +…+ nums[x]
      prefixSum[x] = nums[0] + nums[1] +…+ nums[x]
    
  • 所以有,nums 某一项 = 两个相邻前缀和之差:

      nums[x] = prefixSum[x] - prefixSum[x - 1]
      nums[x] = prefixSum[x] - prefixSum[x - 1]
    
  • 所以有,nums 的 第 i 到 j 项 的总和:

      nums[i] +…+ nums[j] = prefixSum[j] - prefixSum[i - 1]
      nums[i] +…+ nums[j] = prefixSum[j] - prefixSum[i - 1]
    
  • i 可以为 0 ,则 i - 1 为 - 1,我们让 prefixSum[-1] 为 0

题目等价转化:

  • 从【有几种 i、j 组合,使得从第 i 到 j 项的子数组的求和 === k】

↓ ↓ ↓ 转化为 ↓ ↓ ↓

  • 【有几种 i、j 组合,满足 i < j 且 prefixSum[ j ] - prefixSum[ i - 1 ] === k】

  • 目标:求出 prefixSum 数组的每一项,再看哪些项相减 === k,统计 count

  • 但通式有 i, j 两个变量,还得两层 for 循环,时间复杂度依旧 O(n^2)

摈弃 prefixSum 数组,降低时间复杂度

  • 可以不用 prefixSum 数组吗?可以。
  • 因为我们不关心 前缀和 具体对应哪一项,只关心 前缀和 的值和 出现次数
  • 用 prefixSum 变量,保存当前项的前缀和,存入 map
  • 这样 map 代替了 prefixSum 数组,记录出现过的 前缀和出现次数

核心流程

  • map 存什么键值对:

    • 键: 前缀和,即从第 0 项到当前项的总和
    • 值: 这个 前缀和 值出现了几次
  • 在遍历 nums 数组之前,我们让前缀和初始值为 0(即 prefixSum[-1] = 0)。即 map 初始放入 0:1 键值对

  • 遍历 nums 的每一项,求当前项的前缀和,记录到 map

    • 之前没有存过,则存入,初始值为 1
    • 之前存过,则对应值 +1,即出现次数 +1
  • 如果遍历过程中发现,map 中已存在 key当前前缀和 - k

    • 说明存在 【之前求出的前缀和】,它的值满足 【当前前缀和】-【之前求出的前缀和】 === k
    • 【之前求出的前缀和】 出现的次数,累加给 count 计数器

一句话总结

根据 当前前缀和,在 map 中寻找【相减 === k】的 目标前缀和。目标前缀和是一个数值,出现这个数值可能不止 1 次,假设为 n 次,就等价于,找到 n 个连续子数组的求和 === k,遍历 nums 数组,不断把 n 累加给 count,最后返回 count

代码

时间复杂度 O(n) 。空间复杂度 O(n)

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);
        }
        return count;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/he-wei-kde-zi-shu-zu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
参考/搬运:
作者:hyj8
链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/solution/dai-ni-da-tong-qian-zhui-he-cong-zui-ben-fang-fa-y/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(力扣:和为K的子数组)