You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么我的最长连续序列(Longest Consecutive Sequence)解法返回的最大值无法超过65537?

问题分析与修复:ConcurrentHashMap导致长数组下最长连续序列计算错误

你的观察完全精准——这个bug确实和ConcurrentHashMap的使用直接相关,核心问题出在遍历keySet时的元素遗漏,尤其是当元素数量超过65536(2^16)时会触发这个异常表现。

问题根源拆解

ConcurrentHashMap的keySet迭代器是弱一致性的,虽然不会像普通HashMap那样抛出ConcurrentModificationException,但当你在遍历过程中频繁调用remove()修改集合结构时,迭代器可能会跳过部分元素。对于你测试的连续整数数组(0到n-1),这些元素的哈希值就是自身,会均匀分布在ConcurrentHashMap的桶中;当元素数量超过65536时,ConcurrentHashMap的内部扩容逻辑会触发,导致遍历过程中部分后续元素被迭代器忽略,最终你只计算到了前65537个元素的连续长度。

另外,你的代码里还有一个容易被忽略的小错误:在while循环中,你写的是numMap.remove(n - 1),但实际应该移除的是n - lessThan - 1——这个笔误会导致长连续序列中只有第一个前置元素被移除,后续元素仍留在map中,进一步加剧计算错误。

修复方案

方案1:替换为普通HashMap(单线程场景最优)

你的代码是单线程执行的,完全不需要线程安全的ConcurrentHashMap。我们只需要先把keySet转成独立的ArrayList副本再遍历,避免遍历原集合时修改导致的问题:

public int longestConsecutive(int[] nums) { 
    Map<Integer, Boolean> numMap = new HashMap<>(); 
    Map<Integer, Integer> maxMap = new HashMap<>(); 
    for (int i : nums) { 
        numMap.put(i, false); 
    } 
    int max = 0; 
    // 遍历keySet的副本,避免原集合修改影响遍历
    for (int n : new ArrayList<>(numMap.keySet())) { 
        if (!numMap.containsKey(n)) { // 跳过已经被移除的元素
            continue;
        }
        numMap.remove(n); 
        if (maxMap.containsKey(n - 1)) { 
            maxMap.put(n, maxMap.get(n - 1) + 1); 
            max = Math.max(maxMap.get(n), max); 
            continue; 
        } 
        int lessThan = 0; 
        // 修正移除对象的错误
        while (numMap.containsKey(n - lessThan - 1)) { 
            numMap.remove(n - lessThan - 1); 
            lessThan++; 
        } 
        int currentLength = lessThan + 1;
        maxMap.put(n, currentLength); 
        max = Math.max(currentLength, max); 
    } 
    return max; 
}

方案2:优化为更简洁的HashSet解法

其实你不需要维护两个Map,标准的最长连续序列解法用HashSet就可以实现O(n)时间复杂度,还能避免所有遍历相关的问题:

public int longestConsecutive(int[] nums) {
    Set<Integer> numSet = new HashSet<>();
    for (int num : nums) {
        numSet.add(num);
    }
    int maxLength = 0;
    for (int num : numSet) {
        // 只从连续序列的起点开始计算,避免重复统计
        if (!numSet.contains(num - 1)) {
            int currentNum = num;
            int currentLength = 1;
            while (numSet.contains(currentNum + 1)) {
                currentNum++;
                currentLength++;
            }
            maxLength = Math.max(maxLength, currentLength);
        }
    }
    return maxLength;
}

测试验证

修改后的代码可以通过所有长度的测试用例,包括你之前失败的i=65538及更大的数组场景。

内容的提问来源于stack exchange,提问作者user16037629

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:13:15