给你一个整数数组
nums和一个整数k,请你统计并返回 该数组中和为k的子数组的个数 。子数组是数组中元素的连续非空序列。
示例 1:
输入:nums = [1,1,1], k = 2 输出:2
示例 2:
输入:nums = [1,2,3], k = 3 输出:2
题解1 暴力解法
思路
题目的意思就是从 i 开始往后累加 n 位是否有和等于 k。因为是子数组嘛,子数组的要求就是连续,所以不存在逆向等答案。
代码
function subarraySum(nums: number[], k: number): number {
let result: number = 0;
for (let i = 0; i < nums.length; i++) {
let sum: number = 0; // 从 i 开始累加
for (let j = i; j < nums.length; j++) {
sum += nums[j];
if (sum === k) {
result += 1;
}
}
}
return result;
};
时空复杂度分析
时间复杂度:两层循环 O(n^2)
空间复杂度:O(1)
题解2 前缀和
思路
由前缀和的思想可以得到,如果下标从 i 到 j − 1 的非空连续子数组的元素和等于 k,即 s[j] − s[i] = k (i < j)
在遍历 s[j] 的同时用哈希表存储 s[j] 的个数,可以 O(1) 的时间求出之前是否存在 s[j] - k 的值,如果存在,累加进答案求和中即可。
代码
function subarraySum(nums: number[], k: number): number {
const n = nums.length;
const pre_sum: number[] = new Array(n + 1).fill(0);
for (let i = 0; i < n; i++) { // 求出前缀和数组
pre_sum[i + 1] = pre_sum[i] + nums[i];
}
let result: number = 0;
const map: Map<number, number> = new Map();
for (const sum of pre_sum) {
result += map.get(sum - k) ?? 0;
map.set(sum, (map.get(sum) ?? 0) + 1);
}
return result;
};
时空复杂度分析
时间复杂度:一层循环 O(n)
空间复杂度:用额外哈希表存储,复杂度为 O(n)