题目描述

image.png

解题思路

注意题目没有说清楚,子数组是连续的。使用滑动窗口不可取,数字可能为负数。

枚举

image.png
就是双指针,一个指针指向一个数字,另一个指针往前移动,当等于sum,计数器加一。

  1. // 暴力枚举(注意题目要求连续的)
  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 end = start; end >= 0; end--) {
  7. sum += nums[end];
  8. if (sum == k) {
  9. count++;
  10. }
  11. }
  12. }
  13. return count;
  14. }

image.png

前缀和 + 哈希表优化

官解的思路:🔗
image.png
我的理解:
pre[i]=pre[j - 1]+nums[i],这个公式是代表[j,i]相差的数字为nums[i],而本题我们需要求k的连续子数组,所以可以替换为pre[i] - pre[j-1] == k。
进一步替换就为pre[j-1] ==pre[i] - k ,所以每次到pre[i]时,需要求有多少个子数组,我们只需要知道pre[j-1]有多少次即可,可以每次遍历使用hash表记录次数。
但此时p[j-1]就是前缀和,p[i]就是所有的和,所以我们可以使用pre变量来记录每次遍历的所有和,p[j-1]记录在hash表。

注意:为什么先放一个0,因为当pre[i]==k时,也算一个数组,所以0出现一次。

image.png

  1. public int subarraySum(int[] nums, int k) {
  2. Map<Integer, Integer> map = new HashMap<>();
  3. int count = 0, pre = 0;
  4. // 先放入0,表示和为0已经出现了一次
  5. map.put(0, 1);
  6. for (int i = 0; i < nums.length; i++) {
  7. pre += nums[i];
  8. if (map.containsKey(pre - k)) {
  9. // 获取前面前缀和的次数
  10. count += map.get(pre - k);
  11. }
  12. map.put(pre, map.getOrDefault(pre, 0) + 1);
  13. }
  14. return count;
  15. }