Hot100-Day22-T560和为k的子数组

3 阅读2分钟

Day22[26/3/22]T560和为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

解题思路

采用前缀和+哈希表解决

前缀和可以很轻松的求取某一个区间的和,比如说,你想求取 nums[i...j] 的和,那么就可以用 prefix_sum[j + 1] - prefix_sum[i] 来算。然后前缀和也很容易实现,就是循环 nums[i] += nums[i - 1] 就可以把原来的数组变成前缀和了。

哈希表则是查找元素的速度极快,复杂度是 O(1)。

所以可以一边计算前缀和,然后一边查找,当前前缀和减去目标值之后,这个数字存不存在,存在的话,有几个,这样就可以统计,以当前元素为结尾时,和为 k 的字串的个数了。

然后有一个小细节,就是,你得考虑从第一个元素开始统计的字串,你得怎么计算,得要减去 0,所以初始化哈希表的时候,需要放入{0 , 1}.

Code

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

class Solution
{
public:
    int subarraySum(vector<int> &nums, int k)
    {
        unordered_map<int, int> mp{
            {0, 1}};
        int count = 0;
        // 对于[0]元素要特别处理
        if (nums[0] == k)
        {
            count++;
        }
        if (nums[0] == 0)
        {
            mp[0]++;
        }
        else
        {
            mp[nums[0]] = 1;
        }

        for (int i = 1; i < nums.size(); i++)
        {
            // 1. 先求取前缀和
            nums[i] += nums[i - 1];
            // 2. 然后看有无区间存在
            if (mp.count(nums[i] - k))
            {
                count += mp[nums[i] - k];
            }
            // 3. 最后要记得把本次前缀和写入哈希表
            if (mp.count(nums[i]))
            {
                mp[nums[i]]++;
            }
            else
            {
                mp[nums[i]] = 1;
            }
        }
        return count;
    }
};

auto main() -> int
{
    Solution sol;
    vector<int> nums{1, 2, 3};
    int k = 3;

    cout << "result = " << sol.subarraySum(nums, k) << endl;
}