我正在尝试一种方法,从链接列表“ L1”中删除集合“ L2”值的所有外观。我想知道如何去做。目前,我正在考虑从集合“ L2”的值中创建一个HashSet并将其删除,我只是想知道是否有一种方法可以使时间约束为O(n)。
忘记提及链接列表L1和集合L2均未排序。两者都是整数。
答案 0 :(得分:1)
在元素的链表上调用int a = 24, int b = 3, int c = 12 :
int d = 1
不是O(1);它开着)。因此,您的评估正确无误,即为remove
的每个元素调用remove
将为您提供O(mn)的运行时间。
要使整个删除过程为O(n + m),可以将值过滤到一个临时列表中,然后重建L1,但是您还需要为L2
的元素设置一个集合,以便可以执行该操作过滤器检查O(1)时间。
L2
请注意,我们仅使用public static LinkedList<Integer> removeAll(LinkedList<Integer> L1, Collection<Integer> L2) {
LinkedList<Integer> temp = new LinkedList<>();
HashSet<Integer> L2Set = new HashSet<>(L2); // O(m)
// first filter elements into temp
while (L1.size() > 0) { // n loops
int v = L1.removeFirst(); // O(1)
if (!L2Set.contains(v)) { // O(1)
temp.addLast(v); // O(1)
}
}
// add filtered values back to L1
while (temp.size() > 0) { // About n loops
L1.addLast(temp.removeFirst()); // O(1)
}
return L1;
}
和addLast
,它们是O(1)运算,因此可以线性运行。
这还保留了removeFirst
中元素的原始顺序。
答案 1 :(得分:1)
您可以在LinkedList.removeAll
上使用L1
,如果HashSet
还不是L2
,则将HashSet
用于L1.removeAll(L2 instanceof HashSet ? L2 : new HashSet<>(L2));
:
L1
在更高级别上,此操作会迭代L2
列表,并就地移除每个元素(如果它们属于另一个集合LinkedList.removeAll
)。
在内部,Iterator
使用其contains
遍历其元素,然后使用另一个集合的contains
方法检查是否应删除该元素。如果true
返回Iterator.remove
,它将通过Iterator.remove
方法删除该元素。
现在,在LinkedList
上使用O(1)
是contains
最坏的情况,因为要删除的元素是迭代器当前指向的元素。并且在HashSet
上使用O(1)
是O(n)
的平均值,因此,如果L2
已经是HashSet
,则整个解决方案要么是O(n+m)
,要么是{ {1}}(如果没有)。 (此处n=L1.size()
和m=L2.size()
)。