Leetcode 2845 题解

还是要把自己做题的思路写出来的,但是结果可能还是得去观摩一下题解,无论是大佬写的题解还是leetcode官方写的题解,看完题解后再去反思才能有收获,即使下次遇见一样的题不见得能写出来,但有思路比没思路更重要。

今天写的一题中等题虽然说只能想到前半部分,后半部分打死想不出来,看题解也不是太能理解关于模运算的移相和转换,但是如果只是暴力的话可以过609个样例也已经差不多可以过85%的样例了。

今天就来看看如此令人头疼的题目

对于该题我想了很久的解题思路,所以在一开始我就排除了基于(n*n)的双for循环,但除了这个我也实在想不到另一种优化的方法去避免使用循环

1、使用01数组去维护这个整数数组nums

例如我们测试的值nums为[1,3,6,9],modulo为3,k为0,我们可以将该数组转化为[0,1,1,1],然后我们便可以开始遍历左边界和右边界,window(窗口)大小最小为modulo(3)可以扩充,后得到子数组[0,1,1,1][1,1,1]

2、通过循环遍历使得子数组的cnt达到cnt%modulo=k记为一个趣味子数组

我们观察到这个时间复杂度,很简单便能判断我们的循环遍历是会超时的,第二点的优化则成为了我们的重点对象

通过wxyz大佬的题解对于我来说能稍微理解一下如何通过数学方法对代码进行优化处理,用空间复杂度去换时间复杂度
2845. 统计趣味子数组的数目 - 力扣(LeetCode)

复制代码
class Solution {

    public long countInterestingSubarrays(List<Integer> nums, int modulo, int k) {

        int n = nums.size();

        // prefix[i+1] 表示子数组 [0..i] 中取模为k的元素数量

        int[] prefix = new int[n + 1];

        for (int i = 1; i <= n; i++) {

            prefix[i] = prefix[i - 1] + (nums.get(i - 1) % modulo == k ? 1 : 0);

        }

  

        // 使用哈希表记录 (余数, 出现次数)

        Map<Integer, Integer> countMap = new HashMap<>();

        countMap.put(0, 1); // 初始化

        long ans = 0; // 最终结果

  

        for (int i = 1; i <= n; i++) {

            // 计算当前前缀和对 modulo 取余的结果

            int currentMod = prefix[i] % modulo;

            //System.out.println("currentMod:"+currentMod+"prefix[i]:"+prefix[i]);

            // 在哈希表中查找余数 (currentMod - k) % modulo

            int target = (currentMod - k + modulo) % modulo; // 处理负数的情况

            // 累加哈希表中 target 对应的出现次数

            ans += countMap.getOrDefault(target, 0);

            //System.out.println("countMap.getOrDefault(target, 0):"+countMap.getOrDefault(target, 0));

            //System.out.println("target:"+target+"ans:"+ans);

            // 用当前余数更新哈希表

            countMap.put(currentMod, countMap.getOrDefault(currentMod, 0) + 1);

        }

        return ans;

    }

}

据我的理解就是将上述的01数组转换成了cnt数组[0,1,1,1]->[0,0,1,2,3],为什么会多一个0呢,这是因为我们需要通过prefix[r]-prefix[l-1]去维护数组两个(3-0)%mod=0等同于拥有两个子数组[0,1,1,1]和[1,1,1]

而当我们接触到哈希表+前缀和的题目的时候,好像都需要去初始化哈希表使得countMap.put(0, 1),为了处理从数组开头 [0, j] 的子数组,它代表「前缀和为 0」这个状态在一开始就出现过一次,是一个「虚拟前缀」,确保后续运算能完整覆盖所有子数组情况。

而这里的数学转换说实话很难想到,使用数学转换的方式去枚举右,维护左。

相关推荐
Neil今天也要学习9 分钟前
永磁同步电机无速度算法--基于三阶LESO的反电动势观测器
算法·1024程序员节
机器学习之心18 分钟前
NGO-VMD北方苍鹰算法优化变分模态分解+皮尔逊系数+小波阈值降噪+信号重构,MATLAB代码
算法·matlab·重构·信号重构·ngo-vmd·皮尔逊系数·小波阈值降噪
橘颂TA23 分钟前
【剑斩OFFER】算法的暴力美学——山脉数组的蜂顶索引
算法·leetcode·职场和发展·c/c++
速易达网络34 分钟前
C语言常见推理题
java·c语言·算法
freedom_1024_1 小时前
LRU缓存淘汰算法详解与C++实现
c++·算法·缓存
博语小屋1 小时前
力扣11.盛水最多的容器(medium)
算法·leetcode·职场和发展
Swift社区1 小时前
LeetCode 423 - 从英文中重建数字
算法·leetcode·职场和发展
点云SLAM2 小时前
算法与数据结构之二叉树(Binary Tree)
数据结构·算法·二叉树·深度优先·广度优先·宽度优先
小龙报2 小时前
《算法通关指南:算法基础篇 --- 一维前缀和 — 1. 【模板】一维前缀和,2.最大子段和》
c语言·数据结构·c++·算法·职场和发展·创业创新·visual studio
程序员三藏2 小时前
一文了解UI自动化测试
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例