算法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个不同余数),在性能上是高效的。

相关推荐
宸津-代码粉碎机29 分钟前
AI攻防战升级!基于Spring AI构建Java应用自动免疫安全体系
java·大数据·开发语言·人工智能·python·安全·spring
测试19981 小时前
如何用appium搭建Android自动化测试框架?
自动化测试·软件测试·python·测试工具·职场和发展·appium·测试用例
程序员大雄学编程1 小时前
微积分46. 无穷级数四大核心性质:从理论到实践的全方位解析
python·学习·微积分·学习工具
数字化转型分享点滴1 小时前
## 工厂数字化管理系统的价值体现:构建制造全流程数据闭环
python
203号居民2 小时前
LeetCode hot 100 — 141. 环形链表2
算法·leetcode·链表
2301_800074212 小时前
map,list简单方法
windows·python·list
玖玥拾2 小时前
LeetCode 202 快乐数
算法·leetcode
LuminousCPP2 小时前
数据结构-二叉树(六):BFS层序遍历与完全二叉树判断|复用链式队列 + (N_0=N_2+1) 性质证明
c语言·数据结构·笔记·算法·二叉树·宽度优先
DeepVisionary3 小时前
30B 参数打平 1 万亿参数:Meta 开源 Muse Glimmer,跑分 35 对 36
python·自动化