算法31,前缀和,可被k整除的子数组

解决"统计数组中连续子数组和能被 k整除的个数"问题,我们可以通过 前缀和 + 哈希表 + 同余定理​ 优化时间复杂度(从暴力法的 O(n2)降到 O(n)),以下是详细解题步骤:

一、核心思路:前缀和与同余定理

假设数组的前缀和数组 为 sum(sum[i]表示前 i个元素的和,sum[0]=0,sum[1]=nums[0],sum[2]=nums[0]+nums[1]...)。对于任意子数组 nums[i..j](从第 i个到第 j个元素),其和为 sum[j+1] - sum[i]。

若该子数组和能被 k整除,则需满足:

复制代码
(sum[j+1]−sum[i])%k=0

根据同余定理,上式等价于:

复制代码
sum[j+1]%k=sum[i]%k

因此,问题转化为:统计前缀和余数相同的出现次数------每当遇到与前缀和余数相同的历史记录时,这些记录对应的位置到当前位置的子数组和都能被 k整除。

二、处理余数的符号问题

编程语言中,取模运算对负数的处理可能返回负数(如 Java 中 (-2) \% 5 = -2)。为保证余数在 [0, k-1]范围内,需对余数做修正:

复制代码
r=(sum%k+k)%k

三、哈希表的作用与初始化

  • 哈希表 hash:键为"前缀和的余数",值为"该余数出现的次数"。

  • 初始化 :必须预先存入 <0, 1>,表示"前缀和为 0(未遍历任何元素时)的余数 0 出现 1 次"------这是为了处理"子数组从数组开头开始"的情况(如前缀和本身能被 k整除时)。

四、算法执行流程(以 Java 为例)

复制代码
public int subarraysDivByK(int[] nums, int k) {
    Map<Integer, Integer> hash = new HashMap<>();
    hash.put(0, 1); // 初始:前缀和为0,余数0出现1次
    int sum = 0;    // 记录当前前缀和
    int result = 0; // 记录符合条件的子数组数量
    for (int x : nums) {
        sum += x; // 计算当前前缀和
        // 计算余数(处理负数情况)
        int r = (sum % k + k) % k; 
        // 历史中出现r的次数,都是新增的有效子数组数量
        result += hash.getOrDefault(r, 0);
        // 更新当前余数r的出现次数(供后续元素使用)
        hash.put(r, hash.getOrDefault(r, 0) + 1);
    }
    return result;
}

五、步骤拆解与示例验证

以题目中示例 nums = [4,5,0,-2,-3,1], k=5为例,逐步分析:

遍历元素 x 当前前缀和 sum 修正后余数 r 哈希表操作(查+增) 结果 result变化
初始 - - hash = {0:1} 0
4 4 4 查 r=4→ 0;result += 0→ 0 更新 hash = {0:1, 4:1} 0
5 9 4 查 r=4→ 1;result += 1→ 1 更新 hash = {0:1, 4:2} 1
0 9 4 查 r=4→ 2;result += 2→ 3 更新 hash = {0:1, 4:3} 3
-2 7 2 查 r=2→ 0;result += 0→ 3 更新 hash = {0:1, 4:3, 2:1} 3
-3 4 4 查 r=4→ 3;result += 3→ 6 更新 hash = {0:1, 4:4, 2:1} 6
1 5 0 查 r=0→ 1;result += 1→ 7 更新 hash = {0:2, 4:4, 2:1} 7

最终返回 7,与题目示例一致。

六、关键总结

  • 核心是利用前缀和的差 与同余定理将子数组和问题转化为余数统计问题。

  • 哈希表用于高效统计余数出现次数,避免暴力枚举。

  • 余数修正((sum % k + k) % k)是处理负数的关键,保证余数非负。

  • 哈希表初始化 <0, 1>是为了覆盖"子数组从数组开头开始"的边界情况。

这种方法时间复杂度为 O(n)(仅遍历数组一次),空间复杂度为 O(k)(哈希表最多存 k个不同余数),在性能上是高效的。

相关推荐
启观川2 小时前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
南笙北梦2 小时前
本地开源大模型多轮对话显存泄漏排查与修复实录
python
对空六课2 小时前
指标口径生效时间的版本查询实现
大数据·服务器·前端·算法·数据分析
对空六课2 小时前
RFM分层边界变化的回溯计算
大数据·服务器·前端·数据库·人工智能·算法·数据分析
小羊没烦恼!2 小时前
如何在IIS6,7中部署ASP.NET网站?
数据库·后端·python·web安全·asp.net
一勺思维2 小时前
我为什么把 Agent 的核心逻辑从 LangChain 里搬出来手写
算法
碧海银沙音频科技研究院2 小时前
基于炬芯ATS308X的LE aduio LC3编解码算法功能实现
算法
小蒋观天下2 小时前
厂区人员徘徊游荡判别——基于时序轨迹速度的逗留行为分级算法落地
大数据·人工智能·深度学习·算法·机器学习·ai大模型
程序员清风2 小时前
堆与优先队列:从 Top K 到任务调度
java·数据结构·算法
shaibdoio2 小时前
瞬维AI技术拆解:AI获客智能体的双层漏斗算法原理
大数据·人工智能·算法