Day13(前缀和)——LeetCode2845.统计趣味子数组的数目
1 题目描述
给定一个下标从0
开始的数组nums
,以及整数modulo
和k
。找出并统计数组中趣味子数组的数目:
- 在范围
[l,r]
内,设cnt
为满足nums[i]%modulo==k
的索引i
的数量,并且cnt%modulo==k
。 - 子数组是数组中的一个连续非空的元素序列。
其中一个示例如下:
2 题目分析及解决
考虑[0,i]
中满足nums[i]%modulo==k
的下标i
的数量,设为sum[i]
。若[l,r]是一个趣味子数组,则(sum[r]-sum[l-1])%modulo==k
,因此我们可以一边计算sum[i]
,一边寻找满足(sum[i]-sum[j])%modulo==k
的j
的数量,将所有的j
相加即可得到总的好子数组的数量。
我们计算sum[i]
,需要找到i
之前满足(sum[i]-sum[j])%modulo==k
的sum[j]
的数量,因此我们需要把每个sum[i]%modulo
出现的次数记录下来。而(sum[i]-sum[j])%modulo==k
可以转化为sum[j]%modulo==(sum[i]-k)%modulo
,又我们每次记录的sum[i]%modulo
是正数,所以要保证(sum[i]-k)%modulo
是正数,因此需要sum[i]-k+modulo
保证其是正数。所以我们只需用哈希表记录下每个sum[i]%modulo
出现的次数,然后当寻找以nums[i]
结尾的趣味子数组时,只需找到之前出现过几个(sum[i]-k+modulo)%modulo
即可。
注意一个细节,因为sum[i]
是记录的是[0,i]
符合条件的下标个数,因此若有趣子数组包含nums[0]
,我们需要手动加一个头nums[-1]=0
,因此需要初始化哈希表mp[0]=1
。(若不进行初始化,sum[i]-sum[0]
是[1,i]
,永远取不到nums[0]
)。为什么是初始化mp[0]=1
,因为第一个不为0的sum[i]
,满足(sum[i]-k)%modulo==0
,因此[j,i],0<=j<=i
都是有趣子数组,而要想包含[0,i]
,就需要初始化mp[0]=1
。
具体实现如下;
#include<unordered_map>
class Solution {
public:long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {int preSum=0,n=nums.size();long long ans=0;unordered_map<int,int> mp;mp[0]=1;for(int i=0;i<n;i++){//记录nums[i]及其之前满足nums[j]%m==k的数量preSum+=(nums[i]%modulo==k);ans+=mp[(preSum-k+modulo)%modulo];mp[preSum%modulo]++;}return ans;}
};
3 总结
初始化的细节很容易让人头晕,本人解释的也不是很好,建议读者结合具体例子推导一下。