首页 > 其他分享 >2845. 统计趣味子数组的数目-361

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

时间:2023-09-04 15:22:17浏览次数:44  
标签:cnt modulo nums int 2845 prefix 数组 趣味 361

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

给你一个下标从 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 。

提示:

\[1 <= nums.length <= 10^5\\ 1 <= nums[i] <= 10^9\\ 1 <= modulo <= 10^9\\ 0 <= k < modulo\\ \]

解题思路:

见代码注释

code

class Solution {
public:

    /*
    综合考察以下内容:前缀和 + 哈希表 + 数学

    1. 问题转换 -> 前缀和
    nums[l,r]中nums[i] % m == k 的元素的数目cnt;
    如何快速查询num[l,r]之间的cnt?前缀和
    区间查询:前缀和
    区间更新:差分
    止步于此:如果遍历所有的区间的时间复杂度依然是O(n ^ 2)

    2.两数之和 -> 哈希表
    其实进一步思考得写出前缀和计算公式
    前缀和需要在最前面补上一个0,那么nums[l,r]之间的和为:
    prefix[r + 1] - prefix[l]
    那么最后需要判断的就是:
    (prefix[r + 1] - prefix[l]) % m == k
    也就是需要判断:
    prefix[r + 1] % m - prefix[l] % m == k
    那这样就简单了:两数之和,通过哈希表进行查找:
    已经知道右端点的值:prefix[r+1] - k,那么自然是在哈希表中查找prefix[l] % m

    3. 公式变形
    但是存在得到一个问题是:
    6 % 3 - 2 % 3 = -2
    (6 - 2) % 3 =  1
    大小关系发生了变化
    也就是实际上得有两种情况:负数补上一个m
    (x - y) % 3 = x % 3 - y % 3
    (x - y) % 3 = x % 3 - y % 3 + 3
    综合起来就是:


    不需要补上m:
    prefix[r + 1] % m - prefix[l] % m = k
    prefix[r + 1] % m - k = prefix[l] % m

    需要补上m:
    prefix[r + 1] % m - prefix[l] % m + m = k
    prefix[r + 1] % m - k + m = prefix[l] % m
    
    综合起来就是:
    (prefix[r + 1] % m - k + m) % m = prefix[l] % m
    综合的公式有点没太看懂,但是不综合起来也没什么问题,无非就是判断以下最终的结果负与非负罢了。

    公式推导曲折多变,不熟的话怎么能在有限紧张的时间里面写出来呢?
    接下来就简单:遍历右端点,通过哈希表查询左端点的数目。

    
    */        
    long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {

        int len = nums.size();

        vector<int> prefix(len + 1,0);

        for(int i = 0;i < nums.size();i ++)
        {
            if(nums[i] % modulo == k) prefix[i+1] = (prefix[i] + 1) % modulo;
            else prefix[i+1] = prefix[i];
        }
        
        long long int ans = 0;

        unordered_map<int,int> cnt;
        cnt[0] = 1;
        
        for(int right = 1;right < prefix.size();right ++)
        {
            int target = (prefix[right] - k + modulo) % modulo;
            auto it = cnt.find(target);

            if(it != cnt.end())
            {
                ans += it -> second;
            }

            cnt[prefix[right]] ++;
        }
        
        return ans;
        
    }
};
class Solution {
public:
    //优化掉前缀和数组        
    long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {

        int len = nums.size();

        //vector<int> prefix(len + 1,0);

        //for(int i = 0;i < nums.size();i ++)
        //{
        //    if(nums[i] % modulo == k) prefix[i+1] = (prefix[i] + 1) % modulo;
        //    else prefix[i+1] = prefix[i];
        //}
        
        long long int ans = 0;

        unordered_map<int,int> cnt;
        cnt[0] = 1;
        int prefix = 0;

        for(int i = 0;i < len;i ++)
        {
            if(nums[i] % modulo == k) prefix = (prefix + 1) % modulo;

            int target = (prefix - k + modulo) % modulo;
            auto it = cnt.find(target);

            if(it != cnt.end())
            {
                ans += it -> second;
            }

            cnt[prefix] ++;
        }
        
        return ans;
        
    }
};

标签:cnt,modulo,nums,int,2845,prefix,数组,趣味,361
From: https://www.cnblogs.com/huangxk23/p/17677145.html

相关文章

  • COMP3610编程技巧几点看法
    COMP3610/6361PrinciplesofProgrammingLanguagesAssignment1ver1.1SubmissionGuidelinesDuetime:Aug31,2023,11am(CanberraTime)SubmitapdfviaWattle.Scansofhand-writtentextarefine,aslongastheyarereadableandneat.Pleasereadandsign......
  • 趣味骨骼动画
    选中这个操控点工具打上操控点直接拖动就可以有关键帧了......
  • POJ3617(贪心)
    没啥好说的,书上原题,比较坑就是输出需要每80个换行。//#defineLOCAL#include<cstdio>#include<cstring>#include<algorithm>#defineSIZE2000usingnamespacestd;intmain(void){#ifdefLOCALfreopen("data.in","r",stdin);#endif......
  • 和时间有关的英语趣味小知识
    ​和时间有关的英语趣味小知识   唐迪        2018-01-07        1536和时间有关的英语趣味小知识(一)时间是金,其值无价Timeismoney.(时间就是金钱或一寸光阴一寸金)Timeflies.(光阴似箭,日月如梭)Timehaswings.(光阴去如飞)Timeisafile......
  • 如何开发趣味H5小游戏《在线抓娃娃机》
    作为一个H5游戏开发爱好者,最近写了一款非常有趣的小游戏,即《在线抓娃娃机》(在线体验)。在此总结分享一下开发经验,希望能够对大家有所启发。游戏创意与设计《在线抓娃娃机》是一款受欢迎的街机游戏的在线版本,它将经典的抓娃娃机玩法带入了手机屏幕。玩家可以通过点击按钮控制抓手的......
  • [oeasy]python0085_[趣味拓展]字体样式_下划线_中划线_闪动效果_反相_取消效果
    字体样式回忆上次内容\033xm可以改变字体样式0m-10m之间设置的都是字体效果0m复原1m变亮2m变暗从3m到10m又是什么效果呢??真的可以让文字blink闪烁吗?......
  • [oeasy]python0085_[趣味拓展]字体样式_下划线_中划线_闪动效果_反相_取消效果
    字体样式回忆上次内容\033xm可以改变字体样式0m-10m之间设置的都是字体效果0m复原1m变亮2m变暗  ​ 添加图片注释,不超过140字(可选) 从3m到10m又是什么效果呢?? ​ 添加图片注释,不超......
  • 趣味骨骼动画
    选中一个对象,打上关键帧选中关键帧右键,关键帧辅助,缓动刚开始缓入的快,后面缓入的慢把两个中心点的位置往下面调,如何观察一下两个的属性中间加了缓动之后......
  • [oeasy]python0083_[趣味拓展]字体样式_正常_加亮_变暗_控制序列
    字体样式回忆上次内容上次了解了一个新的转义模式\033逃逸控制字符escesc退出标准输出流进行控制信息的设置可以清屏也可以设置光标输出的位置还能做什么呢?可以设置字符的颜色吗???......
  • [oeasy]python0083_[趣味拓展]字体样式_正常_加亮_变暗_控制序列
    字体样式回忆上次内容上次了解了一个新的转义模式\033逃逸控制字符esc esc让输出退出标准输出流进行控制信息的设置可以清屏也可以设置光标输出的位置  还能做什么呢?可以设置字符的颜色吗???......