边界测试用例未通过:连续子数组和问题代码优化咨询
问题分析与解决方案
你遇到的这个问题核心在于没有严格满足连续子数组长度至少为2的要求,同时原有的滑动窗口逻辑本身就不适合处理这类“子数组和为k倍数”的问题(尤其是k=0或者存在0元素的场景)。
你的代码问题点
在测试用例{0,1,0},k=0时,你的代码初始化curSum = nums[0] = 0,进入i=1的循环后,直接触发了if(curSum==0 && k1==0)的条件返回true,但此时对应的子数组只有第一个元素[0],长度为1,完全不符合题目中“长度至少为2”的要求。
除此之外,你的滑动窗口逻辑还有其他缺陷:
- 当k很大时,会漏掉那些和大于k但其实是k倍数的长段子数组(比如示例2的情况,你的代码可能无法检测到总和为42的子数组);
- 没有考虑到前缀和余数重复的情况(这是解决这类问题的核心思路)。
正确的解决思路:前缀和+哈希表
要判断是否存在长度≥2的连续子数组和为k的倍数,我们可以利用前缀和的余数性质:
- 当k≠0时,如果两个不同位置的前缀和对k取余的结果相同,那么这两个位置之间的子数组和就是k的倍数;
- 当k=0时,我们需要找是否存在两个不同位置的前缀和都是0(因为此时子数组和为0,即0的倍数),且这两个位置的索引差≥2。
具体实现步骤:
- 维护一个哈希表,存储前缀和的余数(或0值)对应的最早出现的索引;
- 初始化哈希表,把
{0: -1}放进去(处理前缀和本身就是k倍数的情况,比如前两个元素和为k); - 遍历数组,计算当前前缀和,根据k是否为0分别处理:
- k≠0时,计算当前前缀和对k取余的结果(题目中是 non-negative 整数,前缀和非负,余数无需处理负数);
- k=0时,直接用前缀和的值作为键;
- 如果当前键已经在哈希表中,且当前索引与哈希表中存储的索引差≥2,说明存在符合条件的子数组,返回
true; - 如果当前键不在哈希表中,就把它和当前索引存入哈希表;
- 遍历结束后返回
false。
修改后的代码
class Solution { public boolean checkSubarraySum(int[] nums, int k) { // 哈希表存储前缀和余数(或0值)对应的最早索引 HashMap<Integer, Integer> remainderMap = new HashMap<>(); remainderMap.put(0, -1); int prefixSum = 0; for (int i = 0; i < nums.length; i++) { prefixSum += nums[i]; int key; if (k != 0) { // 处理k≠0的情况,计算余数 key = prefixSum % k; } else { // k=0时,直接用前缀和作为键 key = prefixSum; } if (remainderMap.containsKey(key)) { // 检查索引差是否≥2 if (i - remainderMap.get(key) >= 2) { return true; } } else { // 只存储最早出现的索引,保证后续索引差最大 remainderMap.put(key, i); } } return false; } }
测试用例验证
对于nums={0,1,0}, k=0:
- 前缀和依次为0,1,1;
- 初始哈希表有
{0:-1}; - i=0时,prefixSum=0,key=0,哈希表中存在,i - (-1)=1 < 2,不返回;
- i=1时,prefixSum=1,key=1,哈希表中没有,存入
{1:1}; - i=2时,prefixSum=1,key=1,哈希表中存在,i -1=1 <2,不返回;
- 遍历结束返回
false,符合预期。
对于你给出的两个示例:
- 示例1
[23,2,4,6,7], k=6:前缀和余数依次为5,1,5,5,0;当i=2时,余数5已在i=0出现过,2-0=2≥2,返回true; - 示例2
[23,2,6,4,7], k=6:前缀和余数依次为5,1,1,5,0;当i=4时,余数0对应索引-1,4 - (-1)=5≥2,返回true。
这样就能完美处理所有边界情况,包括k=0、数组中有0元素的场景。
内容的提问来源于stack exchange,提问作者Encipher
相关产品推荐
相关产品推荐

