LeetCode 每日一题 2845. 统计趣味子数组的数目

2845. 统计趣味子数组的数目

给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k 。

请你找出并统计数组中 趣味子数组 的数目。

如果 子数组 numsl...r 满足下述条件,则称其为 趣味子数组 :

在范围 l, r 内,设 cnt 为满足 numsi % modulo == k 的索引 i 的数量。并且 cnt % modulo == k 。

以整数形式表示并返回趣味子数组的数目。

注意:子数组是数组中的一个连续非空的元素序列。

示例 1:

输入:nums = 3,2,4, modulo = 2, k = 1

输出:3

解释:在这个示例中,趣味子数组分别是:

子数组 nums0...0 ,也就是 3 。

-在范围 0, 0 内,只存在 1 个下标 i = 0 满足 numsi % modulo == k 。

-因此 cnt = 1 ,且 cnt % modulo == k 。

子数组 nums0...1 ,也就是 3,2 。

-在范围 0, 1 内,只存在 1 个下标 i = 0 满足 numsi % modulo == k 。

-因此 cnt = 1 ,且 cnt % modulo == k 。

子数组 nums0...2 ,也就是 3,2,4 。

-在范围 0, 2 内,只存在 1 个下标 i = 0 满足 numsi % modulo == k 。

-因此 cnt = 1 ,且 cnt % modulo == k 。

可以证明不存在其他趣味子数组。因此,答案为 3 。

示例 2:

输入:nums = 3,1,9,6, modulo = 3, k = 0

输出:2

解释:在这个示例中,趣味子数组分别是:

子数组 nums0...3 ,也就是 3,1,9,6 。

-在范围 0, 3 内,只存在 3 个下标 i = 0, 2, 3 满足 numsi % modulo == k 。

-因此 cnt = 3 ,且 cnt % modulo == k 。

子数组 nums1...1 ,也就是 1 。

-在范围 1, 1 内,不存在下标满足 numsi % modulo == k 。

-因此 cnt = 0 ,且 cnt % modulo == k 。

可以证明不存在其他趣味子数组,因此答案为 2 。

提示:

1 <= nums.length <= 105

1 <= numsi <= 109

1 <= modulo <= 109

0 <= k < modulo


题解

这道题的关键是转换趣味数组的条件

设 cnt 为满足 numsi % modulo == k 的索引 i 的数量。并且 cnt % modulo == k

注意到,对于 nums 中的数据,我们只关心 其是否 %modulok
不妨令 nums 中 %modulok 的数据为 1,其余为 0

那么趣味数组的条件就转换为:子数组的和 % modulo == k

子数组的和很自然就是用前缀和 记录

用数组 arr i 记录 nums 从 0 到 i 之和

任意边界为 l,r (l<=r) 的子数组之和即为:arrr - arrl + numsl

那么条件转换为:(arrr - arrl + numsl) % modulo == k

接下来就是对这个式子进行巧妙的转换

由于 k < modulo,则 k==k % modulo
(arrr - arrl + numsl) % modulo == k % modulo

arrr - arrl + numsl 与 k 同余!

同余的相关内容可以看【国际数学竞赛】同余理论(Modulo)

根据同余的性质式子又可以转换为
(arrr - k) % modulo == (arrl - numsl) % modulo (移项)

这就是最终的式子

通过一大番功夫,我们将 r 和 l 移到了式子两边,这样我们就可以枚举 r ,用数组 s 不断记录并维护 r 自身即左边的所有 (arrl - numsl) % modulo 的个数。对于每一个 r ,满足条件的左边界个数即为 s(arr\[r - k) % modulo]


代码如下↓

cpp 复制代码
class Solution {
public:
    long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {
        vector<int> arr;//arr是前缀和
        int sum=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]%modulo==k)
            {
                nums[i]=1;
                sum++;
            }
            else
            {
                nums[i]=0;
            }//转换成01,这样就变成统计 和 %mod 为 k 的子数组
            arr.push_back(sum);
        }
        //就是找 (arr[j] - arr[i]+nums[i]) % mod == k
        //等价于 (arr[j] - arr[i]+nums[i]) % mod == k%mod
        //同余
        //(arr[j] - k)%mod == (arr[i] - nums[i])% mod (i<=j)
        //这样就枚举j,统计左边有多少 arr[i] % mod 与之相等即可
        //(arr[i] - nums[i])% mod 可以一边枚举 j 一边维护,O(N)!
        int n=nums.size();
        vector<int> s(min(modulo,n+1));
        long long res=0;
        for(int i=0;i<arr.size();i++)
        {
            int x=(arr[i] - k)%modulo;//哇,小心 arr[i]-k < 0
            if(x<0)
            {
                s[(arr[i]-nums[i])%modulo]++;
                continue;
            }
            s[(arr[i]-nums[i])%modulo]++;
            res+=s[x];
        }
        return res;
    }
};
相关推荐
deepseek2330 分钟前
OpenAI三项科学发现拆解:3-SAT亚指数算法挑战ETH,AI科学声明的验证流水线怎么搭
人工智能·算法·openai
梦帮科技34 分钟前
基于幺正李代数连续归一化流的混合量子生成模型 (HQNN-Flow) 完整技术指南(上部分)
网络·人工智能·算法·量子计算
青少儿编程课堂35 分钟前
蓝桥杯青少组 + 全国青少年信息素养大赛 + 电子学会图形化考级|校园推箱子大挑战解析
c++·python·算法·bfs·信息学竞赛
ynchyong43 分钟前
培养程序化思维
leetcode·程序化思维·刷题经验
多弗朗皮卡丘1 小时前
C++STL之空间配置器
开发语言·c++·内存池·空间配置器
牵猫散步的鱼儿1 小时前
Demosaic 和 Remosaic
c++
荆棘鸟智能2 小时前
河道采砂船识别与轨迹追踪怎么做?检测、跟踪与电子围栏实战思路
人工智能·算法·目标检测
CodeYp20192 小时前
第19讲:封装红黑树实现 mymap 和 myset
开发语言·c++·红黑树
揽星河..2 小时前
【初阶数据结构】常见的排序算法
数据结构·排序算法·1024程序员节
DFT计算杂谈2 小时前
GSAS-II X 射线衍射(XRD)数据转换为对分布函数(PDF,Pair Distribution Function)
算法·机器学习·pdf