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

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

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

假设数组的前缀和数组sumsum[i]表示前 i个元素的和,sum[0]=0sum[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 天前
算法竞赛C++常用的STL
c++·算法
默_笙2 天前
🍙 给每个请求过安检:FastAPI 是怎么把校验写进类型注解的
python
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
qq_426003962 天前
启动playwright录制codegen生成自动化测试脚本
python·自动化
虎头金猫2 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
长沙三为智能科技2 天前
家政小程序开发从0到上线:五阶段交付流程与验收清单
python
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
只睡四小时2 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas
m0_547486662 天前
《数据结构教程》全套 PPT课件2026
数据结构