题目:
Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [1,1,1], k = 2
Output: 2
Example 2:
Input: nums = [1,2,3], k = 3
Output: 2
题目分析:连续子数组的和等于k一共有几种情况
思路分析:
1、最简单的方法就是暴力循环,通过两个for循环来相加判断。时间复杂度为n的平方。计算机每秒可以进行数千万到数亿( 10的8次方数量级)的运算,如果超过这个时间,则视为超时。
由于这道题的数组长度区间为1 <= nums.length <= 2 * 10的4次方,明显用n方会超时。不考虑。
2、用空间来换取时间,来达到On的时间复杂度。
首先On的时间复杂度一定是只对数组遍历了一次,在遍历一次的情况下如何灵活的求连续子区间的和?
在计算数组i-j之间的和时,能想到的有两种方法:
- 从i顺序加到j,这个过程又包含了一次遍历
- 使用sum[j] - sum[i - 1]来得到i-j的和
方法1不考虑,因为时间复杂度不满足On。
方法2里,通过sum[j] - sum[i - 1] 计算得到i-j的和,如果 k === i-j,此时Output+1. 根据方法2的思路,我们可以把当前坐标的和存储在Map表里,如果sum[j] - k的值存在于Map表里,则说明sum[j] - sum[i - 1] === k成立,此时存在一个连续子区间的和等于k。
利用方法2,我们可以得到的解题代码如下:
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var subarraySum = function(nums, k) {
var result = 0
var map = new Map()
map.set(0,1)
var presum = 0
for(let i = 0; i < nums.length; i++) {
presum = presum + nums[i]
// sum[j] - sum[i - 1] === k成立,结果加1
if(map.get(presum - k)) {
result = result + map.get(presum - k)
}
// 不存在当前坐标和时,存储在Map里
if(!(map.get(presum))) {
map.set(presum, 1)
} else {
// 如果已经存在于Map表里,说明之前已经有一个连续子区间的
map.set(presum, map.get(presum) + 1)
}
}
return result
};