繁体   English   中英

克服 HashMap 中的快速失败迭代器的方法

[英]Way to overcome fail-fast iterator in HashMap

在竞争性编程中,我正在解决一个给定的问题 - 给定一个非负整数数组nums和一个目标总和S ,我们必须找出从给定数字的总和中获得目标总和的方法数量(其中每个nums[i]可以被视为nums[i]-nums[i]

虽然我遇到了一些主要依赖于使用数组直接访问表的解决方案(假设数字之和不能超过 1000),但我尝试使用 HashMap 来减少所需空间。 我的代码如下 -

    public int findTargetSumWays(int[] nums, int S) {
        Map<Integer, Integer> dp = new HashMap();
        dp.put(nums[0], 1);
        dp.put(-nums[0], dp.getOrDefault(-nums[0], 0) + 1);
        
        for (int i=1; i<nums.length; i++) {
            for (Integer sum : dp.keySet()) {
                dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
                dp.put(sum-nums[i], dp.getOrDefault(sum-nums[i], 0) + 1);
            }
        }
        return dp.get(S);
    }

但是我在运行代码时遇到了 ConcurrentModificationException 。 我试图找到这个问题。 尽管我在迭代中得到了一些概念上的理解,Collections 的视图不能在结构上进行修改,但我无法弄清楚如何找到解决方法。

是不是不可能使用 HashMap(或任何动态数据结构)的解决方案? 任何帮助表示赞赏。

for (Integer sum : dp.keySet()) {
  dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
  // ...
}

如果sum + nums[i]不是 map 中已经存在的键,则会导致 map 的结构修改:也就是说,您正在添加一个新的键/值对。

Javadoc 中所述

所有此类的“集合视图方法”返回的迭代器都是快速失败的:如果 map 在创建迭代器后的任何时间进行结构修改,除了通过迭代器自己的 remove 方法之外,迭代器将抛出 ConcurrentModificationException .

(如果密钥已经在 map 中,您只需修改与该密钥关联的值,这样就可以了)。

解决这个问题的最简单方法是通过将元素复制到例如列表中来获取要迭代的键的快照:

for (Integer sum : new ArrayList<>(dp.keySet())) {

现在,您正在迭代列表,而不是地图的键集,因此您可以自由地在该循环内从结构上修改 map。


与异常问题不同,您的put/getOrDefault更简单地写为:

// dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
// becomes
dp.merge(sum+nums[i], 1, Integer::sum);

ConcurrentModificationException的原因是您在以下循环中迭代dp.keySet()时正在修改dp的键:

for (Integer sum : dp.keySet()) {
    dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
    dp.put(sum-nums[i], dp.getOrDefault(sum-nums[i], 0) + 1);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM