LeetCode560. 和为 K 的子数组 哈希表和前缀和应用

文章讨论了一种使用前缀和和哈希表解决寻找数组中和为k的连续子数组数量的问题。初始的遍历方法由于时间复杂度为O(n^2)导致超时,官方题解通过维护前缀和并利用哈希表存储和的出现次数,将复杂度降低,提高了效率。题解展示了如何利用哈希表在O(n)时间内找到所有匹配的子数组。
摘要由CSDN通过智能技术生成

题目

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

示例 1:

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

思路分析

看到题目后,觉得和kmp很相似,猜测用前缀和能实现最小时间复杂度。但是搞忘了前缀和是啥。后面试着通过遍历nums数组,用sum记录从i到j的nums之和,再通过对sum和k的大小关系进行判断。如果sum小于k,则累加到j,使得sum>=k为止,若sum=k,则ans++,若sum>k,则i=pre+1,sum-=nums[pre],i等于pre,再次进入循环。

但是这种做法是有很大的问题的,他默认所有数都是正数,即当累计和大于k的时候,就将i++,sum减少一个即可。但是实际上nums可以为负数。

后面又通过取nums中的最小负数为min,将其每个数都加上-min,然后在和k进行判断的时候给k那一项加上(j-i+1)*-min进行比较。不过这样也没做出来。

后面看了题解,果然,那种遍历的方法时间复杂度得有O(n^2),会TLE。官方题解采用的是前缀和加哈希表。

官方题解思路回顾

设前缀和为pres[],我们想要的效果是pres[j]-pres[i]=k。如果通过for循环依次判断,时间复杂度还是O(n^2),这道题本身不关注是第ij项之差能实现累计和为k,于是通过引入哈希表unordered_map<int,int> mp;存储前缀和以及对应前缀和出现次数。每次在哈希表mp中查找前缀和presum-k是否存在,如果存在,则令ans+=mp[presum];其实我也不是很清楚这一步到底为什么能转换成这样,但是通过力扣题解评论区大佬给的例子nums=[1,2,3,0,6],k=6来看,好像是将原本的前缀和的形式进行了转移。

需要知识点

1. unordered_map<int,int> mp;//声明哈希表形式
2. vector& nums;int len=nums.size();//vector数组获取数组长度
3. for(auto& i: nums)//通过自动变量i对nums进行遍历,不然的话,要通过迭代器vector::iterator iter=nums.begin();的形式来处理了

题解(其实跟官方的没啥区别。。)

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int> mp;
        mp[0]=1;
        int ans=0,pre=0,sum=0,len=nums.size();
        for(auto& i:nums)
        {
            sum+=i;
            if(mp.find(sum-k)!=mp.end())
            {
                ans+=mp[sum-k];
            }
            mp[sum]++;
        }
        return ans;
    }
};

总结

这道题帮助回顾了前缀和的知识点,还学习了哈希函数的大概用法。不过对这道题的理解还是没有很到位,暂时记录下来,以后想回顾的时候可以翻一翻。类似的哈希函数入门的题还有1. 两数之和1248. 统计「优美子数组」454. 四数相加 II
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值