10.和为K的子数组
示例 1:
输入:nums = [1,1,1], k = 2 输出: 2 解释: 此题 [1,1] 与 [1,1] 为两种不同的情况
示例 2:
输入:nums = [1,2,3], k = 3 输出: 2
解释: [1,2] 与 [3] 为两种不同的情况
方法1: 暴力枚举
思路从start开始遍历,找到以start开始和为K的子数组。
1 class Solution { 2 public int subarraySum(int[] nums, int k) { 3 int count = 0; 4 for(int start = 0;start<nums.length; start++){ 5 int sum = 0; 6 for(int i = start ;i<nums.length;i++){ 7 sum+=nums[i]; 8 if(sum == k){ 9 count++; 10 } 11 } 12 } 13 return count; 14 } 15 }
方法2: 前缀和+哈希表
我们定义 pre[i] 为 [0..i] 里所有数的和,则 pre[i] 可以由 pre[i−1] 递推而来,即:
pre[i]=pre[i−1]+nums[i]
那么「[j..i] 这个子数组和为 k 」这个条件我们可以转化为
pre[i]−pre[j−1]==k
【为什么 j ~ i 减的是pre[j -1] ,例如【1,1,1】k=2. 当i=1;j=0时候 正好满足, 但需要减 j -1,不然就减多了】
简单移项可得符合条件的下标 j 需要满足
pre[j−1]==pre[i]−k
核心思路:
将当前位置的前缀和存入哈希,若存在+1,不存在赋值为1;
遍历 前缀和满足count+
class Solution { public int subarraySum(int[] nums, int k) { // 1. 初始化变量 int count = 0, pre = 0; // count:最终结果(符合条件的子数组个数);pre:当前累计的前缀和 HashMap<Integer ,Integer> map = new HashMap<>(); // key:前缀和值;value:该前缀和出现的次数 map.put(0,1); // 关键:初始化前缀和0出现1次(对应pre[0]=0) // 2. 遍历数组,计算前缀和并统计 for(int end = 0; end<nums.length; end++){ pre += nums[end]; // 累加当前元素,得到「前end+1个元素的前缀和」(对应pre[end+1]) // 3. 核心:查找是否存在 pre-k 的前缀和,存在则累加次数到count if(map.containsKey(pre-k)){ count += map.get(pre-k); // 有多少个pre[j]=pre-k,就有多少个符合条件的子数组 } // 4. 将当前前缀和存入哈希表(更新出现次数) map.put(pre, map.getOrDefault(pre, 0) + 1); } return count; } }

os:有点绕,在理解理解吧

浙公网安备 33010602011771号