[英]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.