如何解决在 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。我试图找到这个问题。虽然我有一些概念上的理解,在迭代中,集合的视图不能在结构上修改,但我无法弄清楚如何绕过它来找到解决方案。
使用 HashMap(或任何动态数据结构)的解决方案是不可能的吗?任何帮助表示赞赏。
解决方法
for (Integer sum : dp.keySet()) {
dp.put(sum+nums[i],dp.getOrDefault(sum+nums[i],0) + 1);
// ...
}
如果 sum + nums[i]
不是映射中已有的键,这会导致映射的结构修改:也就是说,您要添加一个新的键/值对。
如in the Javadoc所述:
这个类的所有“集合视图方法”返回的迭代器都是快速失败的:如果在迭代器创建后的任何时间对映射进行结构修改,除了通过迭代器自己的remove方法之外的任何方式,迭代器都会抛出 ConcurrentModificationException。
(如果键已经在映射中,您只需修改与该键关联的值,这样就可以了)。
解决这个问题的最简单方法是拍摄要迭代的键的快照,方法是将元素复制到例如一个列表:
for (Integer sum : new ArrayList<>(dp.keySet())) {
现在,您正在迭代列表,而不是地图的键集,因此您可以在该循环内自由修改地图的结构。
与异常问题不同的是,您的 put/getOrDefault
行将更简单地写为:
// dp.put(sum+nums[i],0) + 1);
// becomes
dp.merge(sum+nums[i],1,Integer::sum);
,
ConcurrentModificationException
的原因是您在以下循环中迭代 dp
时修改了 dp.keySet()
的键:
for (Integer sum : dp.keySet()) {
dp.put(sum+nums[i],0) + 1);
dp.put(sum-nums[i],dp.getOrDefault(sum-nums[i],0) + 1);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。