这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情
问题描述
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 *该数组中和为 k ***的连续子数组的个数 。
示例 1:
输入: nums = [1,1,1], k = 2
输出: 2
示例 2:
输入: nums = [1,2,3], k = 3
输出: 2
提示:
1 <= nums.length <= 2 * 10^4-1000 <= nums[i] <= 1000-107 <= k <= 10^7
思路分析
首先我们先要理解一下题目意思,题目会给我们一个整数数组 nums 和一个整数 k,我们需要找到整数数组 nums中和为 k 的连续子数组的个数。
我们可以直接遍历数组,枚举每一个左边界,再从左边界往右遍历计算,计算每一个连续子数组的和,找到所有和为k的连续子数组,我们只需要统计和为k的子数组数量即可,具体代码如下:
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var subarraySum = function(nums, k) {
let res = 0;
for(let i = 0; i < nums.length; i++){
let sum = 0;
for(let j = i; j < nums.length; j++){
sum += nums[j];
if(sum == k) res++;
}
}
return res;
};
直接遍历枚举我们需要进行两重循环,这样的时间复杂度为O(n^2),那么我们还有没有更优的解法呢?我们知道前面方法的瓶颈在于对每个 i,我们需要枚举所有的 j 来判断是否符合条件,我们可以对这一步进行优化,我们可以构建前缀和数组,并使用哈希表记录每一个前缀和的值出现的次数,以快速计算区间和。
- 前缀和:nums 的第 0 项到 当前项 的和。
prefixSum[x] = nums[0] + nums[1] + … + nums[x]
我们只需要一次遍历,以前缀和的值为key,使用哈希表记录每一个前缀和出现的次数,边存边查看 map,如果 map 中存在 key 为「当前前缀和 - k」,说明这个之前出现的前缀和,满足「当前前缀和 - 该前缀和 == k」,它出现的次数,累加给 count。这样的解法时间复杂度 O(n) 。空间复杂度 O(n)。
具体代码如下:
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var subarraySum = function(nums, k) {
const map = {0:1};
let count = 0, sum = 0;
for (const x of nums) {
sum += x;
count += (map[sum - k] || 0);
map[sum] = (map[sum] || 0) + 1;
}
return count;
};
说在后面
本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。