LeetCode算法心得——和可被 K 整除的子数组(前缀和+HashMap)

大家好,我是晴天学长,同余定理的应用,需要的小伙伴可以关注支持一下哦!后续会继续更新的。


1) .和可被 K 整除的子数组

题目描述

给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。

示例:

输入:A = [4,5,0,-2,-3,1], K = 5 输出:7

解释:

有 7 个子数组满足其元素之和可被 K = 5 整除: [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

示例 2:

输入: nums = [5], k = 9
输出: 0


2) .算法思路

前缀和+HashMap

解析:

我们需要求出满足条件的区间,见下图

我们需要找到满足,和为 K 的区间。我们此时 presum 是已知的,k 也是已知的,我们只需要找到 presum - k区间的个数,就能得到 k 的区间个数。但是我们在当前题目中应该怎么做呢?见下图。

我们在之前的例子中说到,presumj+1 - presumi 可以得到 numsi + numsi+1+... numsj,也就是i,j区间的和。

那么我们想要判断区间 i,j 的和是否能整除 K,也就是上图中紫色那一段是否能整除 K,那么我们只需判断

(presumj+1 - presumi ) % k 是否等于 0 即可,

我们假设 (presumj+1 - presumi ) % k == 0;则

presumj+1 % k - presumi % k == 0;

presumj +1 % k = presumi % k ;

我们 presumj +1 % k 的值 key 是已知的,则是当前的 presum 和 k 的关系,我们只需要知道之前的前缀区间里含有相同余数 (key)的个数。则能够知道当前能够整除 K 的区间个数。见下图

我们看到上面代码中有一段代码是这样的
int key = (presum % K + K) % K;

这是为什么呢?不能直接用 presum % k 吗?

这是因为当我们 presum 为负数时,需要对其纠正。纠正前(-1) %2 = (-1),纠正之后 ( (-1) % 2 + 2) % 2=1 保存在哈希表中的则为 1.则不会漏掉部分情况,例如输入为 -1,2,9,K = 2如果不对其纠正则会漏掉区间 2 此时 2 % 2 = 0,符合条件,但是不会被计数。

那么这个题目我们可不可以用数组,代替 map 呢?当然也是可以的,因为此时我们的哈希表存的是余数,余数最大也只不过是 K-1所以我们可以用固定长度 K 的数组来模拟哈希表。


3) .算法步骤

1.创建一个HashMap对象 map 用于存储余数与对应出现次数的映射关系。

2.初始化变量 PerSum 为0,表示当前位置的前缀和。

3.初始化变量 answer 为0,表示满足条件的子数组个数。

4.将余数为0的初始情况放入 map 中,即前缀和为0的情况,出现次数为1。

5.使用一个循环遍历数组中的元素。

6.将当前元素的值累加到 PerSum 中,即计算当前位置的前缀和。

7.使用同余定理,计算当前前缀和除以k的余数,由于负数取模的结果可能为负数,为8.确保结果为非负整数,需要进行加k再取模的操作。

9.检查 map 中是否包含当前余数,如果是,则将对应的出现次数加到 answer 中。

10.将当前余数和对应的出现次数放入 map 中,更新映射关系。

11.循环结束后,返回 answer,表示满足条件的子数组个数。


4).代码示例

java 复制代码
class Solution {
    public int subarraysDivByK(int[] nums, int k) {
         Map<Integer, Integer> map = new HashMap<Integer, Integer>();
            long PerSum = 0;
            int answer = 0;
            map.put(0, 1);
            for (int i = 0; i < nums.length; i++) {
                PerSum += nums[i];
                // 同余定理,因为不符合分配律
                int mod = (int) ((PerSum%k+k)%k);
                if (map.containsKey(mod)) {
                    answer+=map.get(mod);
                }
                map.put(mod, map.getOrDefault(mod, 0) + 1);
            }
            return answer;
    }
}

5).总结

  • 同余定理的运用。

试题链接:

相关推荐
不会代码的小猴18 分钟前
3. 控件学习1
开发语言·c++·笔记·qt·算法
碳基猿1 小时前
案例|普通内容创作者如何利用 CreBee 打造个人内容创业系统:从一个账号到多平台内容资产矩阵
职场和发展·新媒体运营·创业创新·程序员创富·新媒体矩阵
203号居民2 小时前
LeetCode hot 100 —41. 缺失的第一个正数
数据结构·算法·leetcode
专注仿真4 小时前
问答大模型技术方案算法实现-熵权法融合算法 + 交叉编码器重排算法
人工智能·python·算法·语言模型·问答大模型关键算法·熵权融合算法·交叉编码器重排算法
地平线开发者5 小时前
量化为什么会有损失:从量化误差到精度下降
算法
手写码匠6 小时前
华为云Flexus+DeepSeek征文|Dify 多 Agent 会话管理与上下文工程实战:让智能体“记住该记住的,忘掉该忘掉的“
人工智能·深度学习·算法·aigc
2401_862880826 小时前
数据结构 --- 栈
c语言·数据结构·算法
致Great6 小时前
Qwen3.8-27B 接入 DSH 全流程实测:写代码、跑长任务,都没问题
算法
Tisfy7 小时前
LeetCode 3471.找出最大的几近缺失整数:三种情况判断
算法·leetcode·题解·分类讨论
linux-hzh7 小时前
百日算法修炼 · Day 12
算法·深度优先