微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决在 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 举报,一经查实,本站将立刻删除。