560. 和为K的子数组

298 阅读1分钟

题目描述

思路

前缀和 + HashMap, 时间复杂度O(N), 空间复杂度O(N)

暴力枚举,时间复杂度O(N^2),空间复杂度O(1)

枚举所有子数组

代码

前缀和+hashmap

  • 如何利用前缀和?数组中两个元素的前缀和之差可以转化为子数组的各个元素之和
  • 可以O(N^2)内外层遍历数组,用前缀和之差来找出所有“红色子数组和”,同时与target比较计数。时间复杂度仍为O(n^2),空间复杂度成了 O(n)
  • 使用前缀和后,再利用hashmap,map里存放<本数组可能出现的前缀和,该前缀和出现的次数>。遍历一次数组,看preSum[i] - k是否在map中,如果在map中,计数就加上这个前缀和preSum[i] - k出现的次数。
    • 注意:别漏掉preSum[0]preSum[n]构成的前缀和,需要先在map中添加(0,1)

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();//使用map记录出现同样的和的次数
        map.put(0, 1);//这里需要预存前缀和为 0 的情况,会漏掉前几位就满足的情况
        int count = 0;
        int preSum = 0;
        for (int i = 0; i < nums.length; i++) {
            preSum = preSum + nums[i];//计算当前位上的前缀和
            if (map.containsKey(preSum - k)) {
                count  = count + map.get(preSum - k);
            }
            map.put(preSum, map.getOrDefault(preSum, 0) + 1);//记录当前前缀和出现的次数
        }
        return count;
    }
}

暴力

//暴力法 O(N^2)
class Solution {
    public int subarraySum(int[] nums, int k) {
        int l = nums.length;
        int count = 0;
        for (int i = 0; i < l; i++) {
            int sum = 0;
            for (int j = i; j < l; j++) {
                sum += nums[j];
                if (sum == k) {
                    count++;
                }
            }
        }
        return count;
    }
}