LeetCode 算法:和为 K 的子数组c++

原题链接🔗和为 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

题解

前缀和 + 哈希表方法

LeetCode 上的 “和为 K 的子数组” 问题要求找出一个数组中所有和为 k 的连续子数组的个数。这个问题可以通过使用前缀和加哈希表的方法来解决。

  1. 题解
  • 前缀和:首先计算出数组的前缀和,即到当前位置的元素和。

  • 哈希表:使用一个哈希表来存储前缀和出现的次数。这包括了前缀和为0出现的次数,因为任何和为0的子数组都是由其他和为k的子数组通过减法得到的。

  • 双指针(可选):对于更优的空间复杂度,可以使用双指针来避免存储所有的前缀和,而是只存储最近的前缀和。

  • 滑动窗口(可选):与双指针类似,滑动窗口可以在不牺牲时间复杂度的情况下减少空间复杂度。

  • 更新计数:当当前前缀和与 k 的差值在哈希表中存在时,说明找到了一个和为 k 的子数组。此时,更新计数器。

  1. 复杂度
  • 时间复杂度O(N),其中 N为数组的长度。我们遍历数组的时间复杂度为 O(N),中间利用哈希表查询删除的复杂度均为 O(1),因此总时间复杂度为 O(N)。

  • 空间复杂度O(N),其中 N 为数组的长度。哈希表在最坏情况下可能有 N 个不同的键值,因此需要 O(N) 的空间复杂度。

  1. 代码过程
  • 初始化一个变量 prefixSum 为0,用于存储前缀和。
  • 初始化一个空的哈希表 sumCount,键为前缀和,值为该前缀和出现的次数。
  • 初始化计数器 count 为0,用于存储和为 k 的子数组的个数。
  • 遍历数组:
    • 对每个元素 nums[i],更新 prefixSum。
    • 检查 prefixSum - k 是否存在于 sumCount 中,如果存在,count 加上 sumCount[prefixSum - k]。
    • 更新 sumCount[prefixSum],如果 prefixSum 已经存在,增加它的计数,否则设置为1。
  • 返回 count。
  1. 注意事项
  • 确保在更新哈希表时,正确地增加前缀和的出现次数,而不是简单地设置为当前索引。
  • 在计算和为 k 的子数组个数时,需要考虑前缀和为0的情况,因为任何和为0的子数组都可以通过减去另一个和为k的子数组得到。
  1. c++ demo
#include <vector>
#include <unordered_map>
#include <iostream>

using namespace std;

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> sumCount = { {0, 1} }; // 初始化哈希表,前缀和为0出现1次
        int count = 0, prefixSum = 0;

        for (int num : nums) {
            prefixSum += num; // 更新前缀和
            count += sumCount[prefixSum - k]; // 找到和为k的子数组的个数
            sumCount[prefixSum]++; // 更新前缀和的出现次数
        }

        return count;
    }
};

int main() {
    Solution solution;
    vector<int> nums = { 1, 2, 3 };
    int k = 3;
    int subarrayCount = solution.subarraySum(nums, k);

    cout << "The number of subarrays with sum " << k << " is: " << subarrayCount << endl;

    return 0;
}
  • 输出结果:

The number of subarrays with sum 3 is: 2
在这里插入图片描述

前缀和

前缀和是数组中的一个概念,它表示数组从第一个元素到当前元素的和。具体来说,对于一个数组 nums,其前缀和 prefixSums
可以定义如下:
在这里插入图片描述
即,prefixSums[i]nums[0]nums[i] 的和。

前缀和的应用

前缀和在处理涉及数组元素累积和的问题时非常有用,它可以在 O(1)
时间内查询任意两个索引之间的和,而不需要重新计算。以下是一些常见的应用场景:

  1. 查询区间和:快速计算数组中任意两个索引间的和。
  2. 优化某些类型的子数组问题:例如,查找和为特定值的子数组,或查找最大子数组和。
  3. 计算加权平均数:如果数组中的元素代表权重,前缀和可以用来快速计算加权平均数。

前缀和的计算

前缀和可以通过一次遍历数组来构建:
在这里插入图片描述

使用前缀和解决问题

一旦有了前缀和数组,就可以解决一些特定问题,例如:

  • 查找和为 k 的子数组:使用两个指针扩展窗口,当窗口的和等于 k 时,记录解。
  • 最小子数组和:查找使得连续子数组的和大于等于某个特定值的最小长度。

示例

假设有一个数组 nums = [1, 2, 3, 4],其前缀和数组 prefixSums 将会是 [1, 3, 6, 10]

  • prefixSums[0]nums[0] 的值,即 1。
  • prefixSums[1]nums[0] + nums[1] 的值,即 1 + 2 = 3。
  • prefixSums[2]nums[0] + nums[1] + nums[2] 的值,即 1 + 2 + 3 = 6。
  • prefixSums[3]nums[0] + nums[1] + nums[2] + nums[3] 的值,即 1 + 2 + 3 + 4 = 10。

通过前缀和,我们可以快速知道数组中任意区间的和,例如 nums[1] + nums[2] 的和就是 prefixSums[2] - prefixSums[0] = 6 - 1 = 5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码流怪侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值