编码母题 / P0 / 经典算法 / 12
和为K的连续子数组
重要程度必练难度中等预计完成25–35 分钟
题目是什么
输入可含正数、负数和零的整数数组 nums,以及整数 k;返回元素和恰好等于 k 的非空连续子数组个数,不是返回子数组本身;空数组返回 0。
输入输出示例
nums=[1,-1,0]、k=0 时,合法区间为 [1,-1]、[0]、[1,-1,0],返回 3。
练习起手式与验证
/*
* 题目:和为K的连续子数组
* 要求:输入可含正数、负数和零的整数数组 nums,以及整数 k;返回元素和恰好等于 k 的非空连续子数组个数,不是返回子数组本身;空数组返回 0。
* 示例:nums=[1,-1,0]、k=0 时,合法区间为 [1,-1]、[0]、[1,-1,0],返回 3。
*/
function countSubarraysWithSum(nums, k) {}
console.log(countSubarraysWithSum([1, 1, 1], 2)); // 预期:2
console.log(countSubarraysWithSum([1, -1, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([0, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([], 0)); // 预期:0
/*
* 题目:和为K的连续子数组
* 要求:输入可含正数、负数和零的整数数组 nums,以及整数 k;返回元素和恰好等于 k 的非空连续子数组个数,不是返回子数组本身;空数组返回 0。
* 示例:nums=[1,-1,0]、k=0 时,合法区间为 [1,-1]、[0]、[1,-1,0],返回 3。
*/
function countSubarraysWithSum(nums, k) {}
console.log(countSubarraysWithSum([1, 1, 1], 2)); // 预期:2
console.log(countSubarraysWithSum([1, -1, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([0, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([], 0)); // 预期:0解题思路与实现
展开解题思路
当前前缀和为 s 时,之前每个值为 s-k 的前缀都对应一个合法子数组。
function countSubarraysWithSum(nums, k) {
const frequencies = new Map([[0, 1]]);
let prefix = 0;
let count = 0;
for (const value of nums) {
prefix += value;
count += frequencies.get(prefix - k) ?? 0;
frequencies.set(prefix, (frequencies.get(prefix) ?? 0) + 1);
}
return count;
}
// 三组以上可直接运行的验证。
console.log(countSubarraysWithSum([1, 1, 1], 2)); // 预期:2
console.log(countSubarraysWithSum([1, -1, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([0, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([], 0)); // 预期:0
function countSubarraysWithSum(nums, k) {
const frequencies = new Map([[0, 1]]);
let prefix = 0;
let count = 0;
for (const value of nums) {
prefix += value;
count += frequencies.get(prefix - k) ?? 0;
frequencies.set(prefix, (frequencies.get(prefix) ?? 0) + 1);
}
return count;
}
// 三组以上可直接运行的验证。
console.log(countSubarraysWithSum([1, 1, 1], 2)); // 预期:2
console.log(countSubarraysWithSum([1, -1, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([0, 0], 0)); // 预期:3
console.log(countSubarraysWithSum([], 0)); // 预期:0
时间复杂度:O(n)。每个元素只更新一次前缀和与哈希频次。
空间复杂度:O(n)。不同前缀和最多有 n+1 个。