题目链接:https://leetcode.cn/problems/subarray-sum-equals-k/description/
题目:给你一个整数数组 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-10^7 <= k <= 10^7
解法1:枚举、双指针法
时间复杂度:O(n^2)。以下标0开头时,遍历每个子数组;以下标1开头时,遍历每个子数组。。。
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
// 双指针法,start->end
for(int i=0; i<nums.length; i++) {
int sum = 0;
for(int j=i; j<nums.length; j++) {
sum += nums[j];
if (sum == k) {
count++;
}
}
}
return count;
}
}
解法2:前缀和+哈希表
时间复杂度:O(n)。k = 0到下标i的前缀和 - 0到下标j的前缀和,一次遍历计算下标i的前缀和。
定义一个字典map:key为前缀和,value为出现的次数。(如3、0,和为3出现2次,[3]、[3、0] 前缀和都为3)。
定义一个前缀和变量left,遍历到当前元素时,left += nums[i],检查 left - k 是否在字典中,如果在,即是满足条件的一个子数组。
class Solution {
public int subarraySum(int[] nums, int k) {
// 前缀和
int left = 0;
// 子数组和为k的个数
int count = 0;
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
for(int i=0; i<nums.length; i++) {
left += nums[i];
if (map.containsKey(left - k)) {
// +x,而非加1,前缀和为 left-k 可能有多次,每次都是一个case
count += map.get(left - k);
}
// 先判断 left-k 是否存在。检查完毕,再向集合里添加新元素
map.put(left, map.getOrDefault(left, 0) + 1);
}
return count;
}
}
455

被折叠的 条评论
为什么被折叠?



