10.和为 K 的子数组

107 阅读1分钟

题目链接

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

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

示例 1:

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

示例 2:

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

题解1 暴力解法

思路

题目的意思就是从 i 开始往后累加 n 位是否有和等于 k。因为是子数组嘛,子数组的要求就是连续,所以不存在逆向等答案。

代码

function subarraySum(nums: number[], k: number): number {
    let result: number = 0;

    for (let i = 0; i < nums.length; i++) {
        let sum: number = 0; // 从 i 开始累加
        for (let j = i; j < nums.length; j++) {
            sum += nums[j];
            if (sum === k) {
                result += 1;
            }
        }
    }

    return result;
};

时空复杂度分析

时间复杂度:两层循环 O(n^2)

空间复杂度:O(1)

题解2 前缀和

思路

由前缀和的思想可以得到,如果下标从 ij − 1 的非空连续子数组的元素和等于 k,即 s[j] − s[i] = k (i < j)

在遍历 s[j] 的同时用哈希表存储 s[j] 的个数,可以 O(1) 的时间求出之前是否存在 s[j] - k 的值,如果存在,累加进答案求和中即可。

代码

function subarraySum(nums: number[], k: number): number {
    const n = nums.length;
    const pre_sum: number[] = new Array(n + 1).fill(0);

    for (let i = 0; i < n; i++) { // 求出前缀和数组
        pre_sum[i + 1] = pre_sum[i] + nums[i];
    }
    
    let result: number = 0;
    const map: Map<number, number> = new Map();
    for (const sum of pre_sum) {
        result += map.get(sum - k) ?? 0;
        map.set(sum, (map.get(sum) ?? 0) + 1);
    }

    return result;
};

时空复杂度分析

时间复杂度:一层循环 O(n)

空间复杂度:用额外哈希表存储,复杂度为 O(n)