560. 和为 K 的子数组

目录

算法描述

我的暴力解法

官方暴力解法

前缀和+哈希表优化


算法描述

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 

子数组是数组中元素的连续非空序列。

示例 1:

输入:nums = [1,1,1], k = 2
输出:2

示例 2:

输入:nums = [1,2,3], k = 3
输出:2

提示:

  • 1 <= nums.length <= 2 * 104
  • -1000 <= nums[i] <= 1000
  • -107 <= k <= 107

我的暴力解法

class Solution {
    public int subarraySum(int[] nums, int k) {
        int count=0;
        for(int i=0;i

560. 和为 K 的子数组_第1张图片

使用一个for循环从头开始遍历,一个元素一个元素的加,等于k的话,count就加一。

官方暴力解法

public class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        for (int start = 0; start < nums.length; ++start) {
            int sum = 0;
            for (int end = start; end >= 0; --end) {
                sum += nums[end];
                if (sum == k) {
                    count++;
                }
            }
        }
        return count;
    }
}

560. 和为 K 的子数组_第2张图片

原来官方称为枚举。

思路:

考虑以 iii 结尾和为 kkk 的连续子数组个数,我们需要统计符合条件的下标 jjj 的个数,其中 0≤j≤i0\leq j\leq i0≤j≤i 且 [j..i][j..i][j..i] 这个子数组的和恰好为 kkk 。

我们可以枚举 [0..i][0..i][0..i] 里所有的下标 jjj 来判断是否符合条件,可能有读者会认为假定我们确定了子数组的开头和结尾,还需要 O(n)O(n)O(n) 的时间复杂度遍历子数组来求和,那样复杂度就将达到 O(n3)O(n^3)O(n 
3
 ) 从而无法通过所有测试用例。但是如果我们知道 [j,i][j,i][j,i] 子数组的和,就能 O(1)O(1)O(1) 推出 [j−1,i][j-1,i][j−1,i] 的和,因此这部分的遍历求和是不需要的,我们在枚举下标 jjj 的时候已经能 O(1)O(1)O(1) 求出 [j,i][j,i][j,i] 的子数组之和。

作者:力扣官方题解
链接:https://leetcode.cn/problems/subarray-sum-equals-k/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

前缀和+哈希表优化

class Solution {
    public int subarraySum(int[] nums, int k) {
        int n = nums.length;
        int[] sums = new int[n + 1];
        for (int i = 0; i < n; i++) {
            sums[i + 1] = sums[i] + nums[i];
        }

        // key-前缀和, value-前缀和为key的个数
        // 问题转化为和为 k 的问题
        Map map = new HashMap<>();
        int count = 0;
        for (int i = 0; i <= n; i++) {
            // 如果有与当前 sums[i] 差为 k 的则加上它的个数
            count += map.getOrDefault(sums[i] - k, 0);
            // 前缀和的个数
            map.put(sums[i], map.getOrDefault(sums[i], 0) + 1);
        }
        return count;
    }
}

560. 和为 K 的子数组_第3张图片

思路:

//使用前缀和的方法可以解决这个问题,因为我们需要找到和为k的连续子数组的个数。通过计算前缀和,我们可以将问题转化为求解两个前缀和之差等于k的情况。
//
//假设数组的前缀和数组为prefixSum,其中prefixSum[i]表示从数组起始位置到第i个位置的元素之和。那么对于任意的两个下标i和j(i < j),如果prefixSum[j] - prefixSum[i] = k,即从第i个位置到第j个位置的元素之和等于k,那么说明从第i+1个位置到第j个位置的连续子数组的和为k。
//
//通过遍历数组,计算每个位置的前缀和,并使用一个哈希表来存储每个前缀和出现的次数。在遍历的过程中,我们检查是否存在prefixSum[j] - k的前缀和,如果存在,说明从某个位置到当前位置的连续子数组的和为k,我们将对应的次数累加到结果中。
//
//这样,通过遍历一次数组,我们可以统计出和为k的连续子数组的个数,并且时间复杂度为O(n),其中n为数组的长度。

560. 和为 K 的子数组_第4张图片

你可能感兴趣的:(算法,算法,数据结构,leetcode)