简体   繁体   English

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

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

In competitive programming, I was solving a given problem - given an array nums of non-negative integers, and a target sum S , we have to find out the number of ways we can obtain target sum from sum of given numbers (where each nums[i] can be taken as nums[i] or -nums[i] .在竞争性编程中,我正在解决一个给定的问题 - 给定一个非负整数数组nums和一个目标总和S ,我们必须找出从给定数字的总和中获得目标总和的方法数量(其中每个nums[i]可以被视为nums[i]-nums[i]

Although I came across some solutions that mainly relied on direct access tables using array (it is given that sum of numbers cannot exceed 1000), but I tried it using HashMap to reduce the space required.虽然我遇到了一些主要依赖于使用数组直接访问表的解决方案(假设数字之和不能超过 1000),但我尝试使用 HashMap 来减少所需空间。 My code is as follows -我的代码如下 -

    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);
    }

But I am getting ConcurrentModificationException on running the code.但是我在运行代码时遇到了 ConcurrentModificationException 。 I tried finding about the issue.我试图找到这个问题。 Although I got some conceptual understanding that in iteration, view of Collections can't be structurally modified, I am not able to figure out how to find my way around it to find a solution.尽管我在迭代中得到了一些概念上的理解,Collections 的视图不能在结构上进行修改,但我无法弄清楚如何找到解决方法。

Is it that a solution using HashMap(or any dynamic data structure) is not possible?是不是不可能使用 HashMap(或任何动态数据结构)的解决方案? Any help is appreciated.任何帮助表示赞赏。

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

If sum + nums[i] isn't a key that's already in the map, this results in a structural modification of the map: that is, you're adding a new key/value pair.如果sum + nums[i]不是 map 中已经存在的键,则会导致 map 的结构修改:也就是说,您正在添加一个新的键/值对。

As described in the Javadoc :Javadoc 中所述

The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.所有此类的“集合视图方法”返回的迭代器都是快速失败的:如果 map 在创建迭代器后的任何时间进行结构修改,除了通过迭代器自己的 remove 方法之外,迭代器将抛出 ConcurrentModificationException .

(If the key were already in the map, you'd just be modifying the value associated with that key, and this would be fine). (如果密钥已经在 map 中,您只需修改与该密钥关联的值,这样就可以了)。

The easiest way to get around this is to take a snapshot of the keys to iterate over, by copying the elements into eg a list:解决这个问题的最简单方法是通过将元素复制到例如列表中来获取要迭代的键的快照:

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

Now, you're iterating the list, not the map's keyset, so you are free to modifying the map structurally inside that loop.现在,您正在迭代列表,而不是地图的键集,因此您可以自由地在该循环内从结构上修改 map。


Separately from the question of the exception, your put/getOrDefault lines would be more simply written as:与异常问题不同,您的put/getOrDefault更简单地写为:

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

The reason for ConcurrentModificationException is that you are modifying the keys of dp while iterating dp.keySet() in the following loop: 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.

相关问题 失败快速迭代器 - fail-fast iterator 您确切地表示HashMap的迭代器是快速失败而HashTable的枚举器不是吗? - What do you exactly mean by HashMap's iterator is fail-fast and HashTable's enumerator isn't? Java中是否存在一种快速失败的同步方式? - Is there a fail-fast way of synchronization in Java? 使用EL对空属性进行快速故障转移的最简单方法? - Easiest way to fail-fast on an empty attribute using EL? 多个线程在单个集合上使用iterator.remove()返回失败快速迭代器 - Multiple threads using iterator.remove() on a single collection returning fail-fast iterator 为什么Hashmap快速失败不会在调整大小功能中发生? (用于多线程竞争条件问题) - Why Hashmap fail-fast not happen in the resize function? (for multiple thread race condition issue) 为什么HashMap快速失败只是因为它提供了迭代其键的方法? - Why is HashMap fail-fast just because it provides a means to iterate over its keys? 迭代器是快速失败的,而枚举不是。 除Javadoc给出的要点外,两者之间是否还有其他区别? - Iterator is fail-fast and Enumeration is not. Are there additional differences between the two other than the points given by Javadoc? 配置Java Socket以在断开连接时快速失败? - Configure a Java Socket to fail-fast on disconnect? 无法理解此有关快速失败的评论 - Cannot understand this comment about fail-fast
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM