【问题标题】:How to remove elements from LinkedList with nested iterators in javajava - 如何使用Java中的嵌套迭代器从LinkedList中删除元素
【发布时间】:2019-05-14 14:52:22
【问题描述】:

我正在尝试从 Java 中的无序列表中删除重复元素(Cracking the Coding Interview 中的一个问题)。

我在同一个 List 对象上使用嵌套迭代器,但是当我删除一个项目时我得到一个 ConcurrentModificationException。这是我的代码:

Iterator<String> i = list.iterator();   
String curr;
while (i.hasNext()) {
    curr = i.next();
    Iterator<String> j = list.iterator();
    while (j.hasNext()) {
        String runner = j.next();
        if (curr == runner){
            j.remove();
        }
    }
}

书中的解决方案使用了 LinkedListNode 对象,这使得只改变节点的指针成为可能,但是有没有办法只使用java.util.LinkedList 来解决这个问题?

编辑:挑战是在不使用临时缓冲区的情况下做到这一点,否则额外的列表就可以解决问题。

【问题讨论】:

  • 我会将需要删除的节点添加到另一个列表中。使用两个迭代器遍历整个列表后,从主列表中删除也位于“要删除”列表中的项目。
  • 这仍然使用另一个集合,但是当您迭代列表时,您可以将元素添加到Set。如果 Set.add 方法返回 false,则从列表中删除该元素。这样做意味着您不必多次遍历列表(一次查找重复项,第二次+删除所有重复项)。
  • 另外,不要将Strings 与== 比较,使用equalsequalsIgnoreCase
  • 你为什么不简单地这样做list.stream().distinct().collect(Collectors.toList());
  • @VictorGubin .distinct() 调用在内部创建了一个临时的 LinkedHashSet。挑战是在不使用临时缓冲区的情况下做到这一点。我的回答提供了一种方法。

标签: java iterator


【解决方案1】:

如果您不使用迭代器或foreach 循环,您将不会收到ConcurrentModificationException。例如,您可以这样做:

List<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 1, 2, 3));

for (int i = 0; i < list.size() - 1; i++) {
    for (int j = i + 1; j < list.size(); j++) {
        if (list.get(i).equals(list.get(j))) {
            list.remove(j);
            j--;
        }
    }
}

System.out.println(list); // [1, 2, 3]

【讨论】:

  • 感谢您的回答!它的运行时间是什么,包括从列表中检索项目?
  • 对不起,你能重新提出这个问题吗?
  • 由于链表的属性,我假设使用list.get(i) 的运行时间为 O(i)。包括这个,这个算法的总运行时间是多少?
  • 我猜它会是 O(n^3),因为 list.get(i) 需要 O(n/2) ~ O(n),而我们有嵌套循环 ~O(n ^2),因此我们有 O(n*n^2)~O(n^3)。它不是最好的算法,但它不使用其他缓冲区。如果我错了,请纠正我。
【解决方案2】:

以下是不使用任何临时附加集合的 O(N^2) 算法。向后迭代,从最后一个元素到第二个元素,如果列表的当前元素已经存在于列表的前面,则删除当前元素。

public static void removeDuplicates(List<?> list) {
    ListIterator<?> iter = list.listIterator(list.size());
    for (int index = list.size() - 1; index > 0; index--) {
        Object element = iter.previous();
        if (list.subList(0, index).contains(element))
            iter.remove();
    }
}

测试:

@Test
void removeDuplicatesShouldRemoveAllDuplicates() {
    List<Integer> list = new LinkedList<>(Arrays.asList(1,2,1,3,1,4,5,5,1));
    Main.removeDuplicates(list);
    assertEquals(Arrays.asList(1,2,3,4,5), list);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多