#560 Subarray Sum Equals K

Description

Given an array of integers nums and an integer k, return the total number of continuous subarrays whose sum equals to k.

Examples

Example 1:

Input: nums = [1,1,1], k = 2
Output: 2

Example 2:

Input: nums = [1,2,3], k = 3
Output: 2

Constraints:

1 <= nums.length <= 2 * 1 0 4 10^4 104
-1000 <= nums[i] <= 1000
- 1 0 7 10^7 107 <= k <= 1 0 7 10^7 107

思路

最开始的时候我想用的是类似于KMP的算法,类似于动态窗口的方式,一点点往前挪动

class Solution {
    public int subarraySum(int[] nums, int k) {
        int answer = 0;
        int pointer = 0;
        int tempSum = 0;
        
        for(int i = 0; i < nums.length; i++){
            tempSum += nums[i];
            
            while (tempSum > k){
                tempSum -=nums[pointer];
                pointer ++;
            }
            
            if (tempSum == k && i - pointer >= 0){
                answer ++;
                tempSum -=nums[pointer];
                pointer ++;
            }
        }
        
        return answer;
    }
}

但貌似这个方法只适用于全正数的情况,对下面这种样例就wrong answer了

[-1, -1, 1]
0

然后就想不出了,老老实实用了暴力求解 O(n^2)

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

居然能ac!我还以为会TLE,虽然时间上是1227ms

但是这道题肯定有tricky的解法!翻了下discussion,就是用Map(比较类似于 #1 two sum)。这道题的map用的映射关系是

  • [ 0 , i ] [0, i] [0,i] 的和 (记为 preSum) → 和为 preSum 的 i i i 的个数

这样有什么好处呢?
假设我们现在位于位置 j j j,且 [ 0 , j ] [0,j] [0,j] 和为 sum。我们的目标是寻找一段连续的子串,让这个连续子串的和为 k k k,且已知 [ 0 , j ] [0,j] [0,j] 和为 sum。那么到节点 j j j 为止,满足连续子串和为 k k k 的个数就是

  • map [sum - k]

不难理解,存在多少个 i i i,就存在多少个满足条件的连续子串。

第一个问题解决了,接下来是可能碰到的第二个问题,怎么处理第一个碰到的满足条件的连续子串?
这种情况下 sum - k = 0,但是前面的计数过程中 [可能] 并没有出现 map[0] 的情况,因此我们在map中需要初始化一个原始情况

  • map [0] = 1

也就是将开始处理前的状态所拥有的值置为1

理论讲到这里,可以举个例子。

[-1, -1, 1, 0]
0

  • 初始化 map[0] = 1,sum = 0,nums = [-1, -1, 1, 0],count = 0
  • 处理第 1 个数 -1
    • sum[0, 1] = 1
    • sum - k = -1
    • map[sum-k] 没有值,意味着没有 [ 0 , i ] [0,i] [0,i] 的子串符合条件,所以为0
      • count += 0(count = 0)
    • map[-1] = map[-1] + 1 = 0 + 1 = 1
  • 处理第 2 个数 -1
    • sum[0, 2] = -2
    • sum - k = -2
    • map[sum-k] 没有值,意味着没有 [ 0 , i ] [0,i] [0,i] 的子串符合条件,所以为0
      • count += 0(count = 0)
    • map[-2] = map[-2] + 1 = 0 + 1 = 1
  • 处理第 3 个数 1
    • sum[0, 3] = -1
    • sum - k = -1
    • map[sum-k] = 1,有值了,说明前面有 1 个 [ 0 , i ] [0,i] [0,i] 子串( i = 1 i=1 i=1)符合条件
      • count += map[sum-k] (count = 1)
    • map[-1] = map[-1] + 1 = 1 + 1 = 2
  • 处理第 4 个数 0
    • sum[0, 4] = -1
    • sum - k = -1
    • map[sum-k] = 2,有值了,说明前面有 2 个 [ 0 , i ] [0,i] [0,i] 子串( i = 1 i=1 i=1 i = 3 i=3 i=3)符合条件
      • count += map[sum-k] (count = 3)
    • map[-1] = map[-1] + 1 = 2 + 1 = 3

最后答案就是 count = 3

代码

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);
        
        int sum = 0, count = 0;
        
        for(int i = 0; i < nums.length; i++) {
            sum += nums[i];
            
            if(map.containsKey(sum - k)) {
                count += map.get(sum-k);
            }
            
            map.put(sum, map.getOrDefault(sum, 0) + 1);
        }

        return count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值