[leetcode] 560. Subarray Sum Equals K

时间:2023-02-09 16:23:08

前言

这道题目难度为 Medium,想了挺久的,觉得还是应该记录下来(可能对大神们来说比较简单。。)

题目

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

示例:

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

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

解法一

最简单最直接的解法就是暴力搜索,双重循环遍历数组,依次相加当前数字,和满足 K就记录下来,继续遍历,直到数组遍历完毕。

/** * @param {number[]} nums * @param {number} k * @return {number} */
var subarraySum = function(nums, k) {
    var res = 0;
    var sum = 0;

    for(var i = 0; i < nums.length; i++) {
        sum = nums[i];
        if(sum == k) ++res;
        for(var j = i + 1; j < nums.length; j++) { // 找连续的子数组,j 从 i+1 开始
            sum += nums[j];
            if(sum == k) ++res;
        }
    }

    return res;
};

解法二

解法一虽然直接有效,但是双重循环的时间复杂度会高一点,这道题肯定有用空间来换取时间的解法。
LeetCode 讨论区里比较多的是用哈希表(Hash Table)来解决,接下来重点分析这种方法。

分析

从起始位置开始累加,到 i 节点的和为 sum[i];
从起始位置开始累加,到 j 节点的和为 sum[j];
假设 j > i; 那么当 sum[j] - sum[i] = k 的时候,那么说明存在 (i,j] 之间的子数组之和等于 k,注意这里的取值区间的边界是左开右闭,那是因为这里假设 sum[0] = nums[0],假如设定sum[0] = 0,那么区间取值为[i,j)。举个例子如下:

nums = [1, 2, 3, 4, 5]

假如sum = [1, 3, 6, 10, 15],sum[3] - sum[1] = 7,说明num[2] + num[3] = 7,下标从 i + 1 开始算,不包括 i;
假如sum = [01, 3, 6, 10, 15],sum[4] - sum[2] = 7,说明num[2] + num[3] = 7,下标从 i 开始算,不包括 j;

记录sum[i]的值到哈希表中,假如哈希表存在 sum[j] - k,那么一定存在连续和为 K 的子数组

代码

/** * @param {number[]} nums * @param {number} k * @return {number} */
var subarraySum = function(nums, k) {
    var res = 0;
    var sum = 0;

    var map = new Map();
    map.set(0, 1);
    for(var i = 0; i < nums.length; i++) {
        sum += nums[i];

        if(map.get(sum - k)) {
            res += map.get(sum - k);
        }
        if(map.get(sum)) {
            map.set(sum, map.get(sum) + 1); // 哈希表已经存在这个值,那么这个值需要 +1,说明之间存在不止一个子数组和等于 k;
        } else {
            map.set(sum, 1);
        }
    }

    return res;
};

举例

还是举例说明直观一点:

// 示例1
nums = [1, 1, 1, 1], k = 2;
sum = 0;
res = 0;
map: 0 => 1;
sum = 1;
1 - 2 = -1; // 表中不存在,res 不变
//将sum = 1存到哈希表中
map: 0 => 1, 1 => 1;
sum = 2;
2 - 2 = 0; // 表中存在map.get(0) == 1
res = 0 + map.get(0) = 1;
//将sum = 2存到哈希表中
map: 0 => 1, 1 => 1, 2 => 1;
sum = 3;
3 - 2 = 1; // 表中存在map.get(1) == 1
res = 1 + map.get(1) = 2;
//将sum = 3存到哈希表中
map: 0 => 1, 1 => 1, 2 => 1, 3 => 1;
sum = 4;
4 - 2 = 2; // 表中存在map.get(2) == 1
res = 2 + map.get(2) = 3;
// 数组遍历结束,结果返回3

// 示例2
nums = [1, -1, 5, -2, 3], k = 3;
sum = 0;
res = 0;
map: 0 => 1;
sum = 1;
1 - 3 = -2; // 表中不存在,res 不变
//将sum = 1存到哈希表中
map: 0 => 1, 1 => 1;
sum = 0;
0 - 3 = -3; // 表中不存在,res 不变
//将sum = 0存到哈希表中,由于表中存在 0 => 1,所以把值 +1
map: 0 => 2, 1 => 1;
sum = 5;
5 - 3 = 2; // 表中不存在,res 不变
//将sum = 5存到哈希表中
map: 0 => 2, 1 => 1, 5 => 1;
sum = 3;
3 - 3 = 0; // 表中存在map.get(0) == 2;
res = 0 + map.get(0) = 2;
//将sum = 3存到哈希表中
map: 0 => 2, 1 => 1, 5 => 1, 3 => 1;
sum = 6;
6 - 3 = 3; // 表中存在map.get(3) == 1;
res = 2 + map.get(3) = 3;
// 数组遍历结束,结果返回3

总结

写的啰嗦了一点,但这是我最能理解这个解法的方式了,努力加油吧~