LeetCode: 560. Subarray Sum Equals K

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

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 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

解法一:(暴力破解)

都会,代码略

解法二:(利用累加和)

这个解法利用的是,如果有a + k = b,那么就必然有b - a = k的原理。a和b为别为数组某两位之前的数字累加和。换句话说,设sum[i]和sum[j] (j>i)分别是数组第i位之前和第j位之前的数字累加和,那么如果有sum[j] - sum[i] == k,那就说明从第i位到第j位上的数字加和等于k。

具体算法:

声明一个Hashmap,key为数组累加和出现的值,value为该值在累加过程中出现的次数。

以[3,4,7,2,-3,1,4,3] k = 7为例,计算过程如下

nums[i]   3 4 7 2 -3 1 4 3
sum[i]
(到第i位为止的累加和)
0 3 7 14 16 13 14 18 21
hashmap key
(到第i位为止出现过的累加和的值)
0 3 7 14 16 13 14 18 21
hashmap value 
(到第i位为止出现过的累加和的值的对应次数)
1 1 1 1 1 1 2 1 1

count = hashmap(sum[i] - k) + 1

0 - 1 2 - - 3 - 5

在上述的计算过程中,第i位之前的累加值两次出现14,在第一次出现14的时候因为14-k = 7,而7恰好在之前出现过一次,那么count就在7出现的次数上加1,得到2。也就是说,在数组遍历到数字7的时候,前面已经有两个数字(3,4)可以组成符合条件的子数组了,那么加上现在的7以后,就可以独立组成另外一组子数组,也就是[(3,4), (7)];而后当sum[i]第二次出现14的时候,14-k继续等于7,那么继续在现有count基础之上加上当前map中7出现的次数,也就是1,得到当前新的count数。也就是说当数组遍历到数字1的时候,在它之前已经有2个符合条件的子数组出现过了,就是刚才的[(3,4), (7)],那么加上现在这个当前值1,就组成了第三个符合条件的数组,即[(3,4), (7),(7,2,-3,1)]。当遍历的最后一个数字3的时候,sum[i]==21,但是21-k == 14,而14又在前面出现过2次,说明从数组最后一位到最近一次出现累加和等于14的位置上,存在符合条件的子数组(4,3),但是为什么这里要把count+2而不是像之前一样+1呢?因为在最近一次(也就是第二次)出现累加和等于14之前,到第一次出现14之间的数字加和是0,因为0和任意数组组合都符合题意要求,所以需要把这次加上。这也就是hashmap要记录每个累加和出现次数的原因,因为只要累加和曾经出现过,那么两次累加和之间的数字加和就一定是0。(否则怎么可能两次累积和的数字一样呢?)

总结一下上面的过程就是,如果在遍历数组的过程中发现sum[i] - k的值曾经出现过,那么就意味着有一个新的符合条件的数组出现,即从第i位到它之前的某一位,但具体是哪一位我们其实不用关心。如果非要关心的话,就是从当前第i位到上一次出现sum[i] - k的值的位置,比如当第二次遇到sum[i] == 14的时候,符合条件的子数组就是从当前位第5位到上一次sum[i] == 14(即第一次sum[i]==14)的时候(i=2),它们之间的数字(7,2,-3,1)。

public static int subarraySum(int[] nums, int k) {
        int count = 0, sum = 0;
        HashMap map = new HashMap<>();
        map.put(0, 1);
        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;
    }

 

你可能感兴趣的:(LeetCode,leetcode)