给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k 。
请你找出并统计数组中 趣味子数组 的数目。
如果 子数组 nums[l…r] 满足下述条件,则称其为 趣味子数组 :
在范围 [l, r] 内,设 cnt 为满足 nums[i] % modulo == k 的索引 i 的数量。并且 cnt % modulo == k 。
以整数形式表示并返回趣味子数组的数目。
注意:子数组是数组中的一个连续非空的元素序列。
示例 1:
输入:nums = [3,2,4], modulo = 2, k = 1
输出:3
解释:在这个示例中,趣味子数组分别是:
子数组 nums[0…0] ,也就是 [3] 。
- 在范围 [0, 0] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0…1] ,也就是 [3,2] 。 - 在范围 [0, 1] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0…2] ,也就是 [3,2,4] 。 - 在范围 [0, 2] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组。因此,答案为 3 。
示例 2:
输入:nums = [3,1,9,6], modulo = 3, k = 0
输出:2
解释:在这个示例中,趣味子数组分别是:
子数组 nums[0…3] ,也就是 [3,1,9,6] 。
- 在范围 [0, 3] 内,只存在 3 个下标 i = 0, 2, 3 满足 nums[i] % modulo == k 。
- 因此 cnt = 3 ,且 cnt % modulo == k 。
子数组 nums[1…1] ,也就是 [1] 。 - 在范围 [1, 1] 内,不存在下标满足 nums[i] % modulo == k 。
- 因此 cnt = 0 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组,因此答案为 2 。
哈希前缀
//(x-y) % m = k 变换 x % m - y % m = k
class Solution {
public:
long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {
int n = nums.size();
unordered_map<int ,int> group;
int count = 0;
long long ans = 0;
group[0] = 1;
for(int i = 0;i < n;i++){
count += nums[i] % modulo == k;
ans += group[(count - k + modulo) % modulo];
group[count % modulo]++;
}
return ans;
}
};
-------------------------------------------------
//力扣930。和相同的二元子数组
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
int sum = 0;
unordered_map<int, int> cnt;
int ret = 0;
cnt[0] = 1;
for (auto& num : nums) {
sum += num;
ret += cnt[sum - goal];
cnt[sum]++;
}
return ret;
}
};
这道题的解题方式和力扣930的解法很相似,也是求满足一定条件的子数组的数量。这道题有几个关键的步骤:
第一个是转换,将符合条件的nums[i]转换成1,否则转换成0。
第二个是要清楚数学公式(x-y) % m = k 变换 x % m - y % m = k
。
第三个是要初始化哈希表,令group[0] = 1。
最后遍历数组,进行统计。
在时间复杂度和空间复杂度上,都是O(n)。但是由于使用数组vector的索引访问速度比 unordered_map更快,因为它是连续内存块,而 unordered_map 需要计算哈希值并进行冲突处理,所以使用数组的效率会更高。
long long countInterestingSubarrays(vector<int> &nums, int mod, int k) {
int n = nums.size();
vector<int> cnt(n + 1);
cnt[0] = 1;
long long ans = 0;
int s = 0;
for (int x: nums) {
if (x % mod == k)
s = (s + 1) % mod;
int s2 = (s - k + mod) % mod;
if (s2 <= n)
ans += cnt[s2];
cnt[s]++;
}
return ans;
}
};
使用数组的原理和哈希表类似。