我们来看两个字符串arraylists
List<String> namesListA = new ArrayList<>(/*50 000 strings*/);
List<String> namesListB = new ArrayList<>(/*400 000 strings*/);
removeAll方法似乎不起作用。后:
namesListA.removeAll(namesListB);
namesListA.size()仍然是50000.编辑:输入数据不正确,它实际上有效但需要很长时间。
我写了以下蛮力代码:
boolean match;
for (String stringA: namesListA)
{
match = false;
for (String stringB: namesListB)
{
if (stringA.equals(stringB))
{
match = true;
break;
}
}
if (!match)
{
finallist.add(stringA);
}
}
但需要8个小时才能完成。它有任何已知的有效搜索字符串算法?喜欢按字母顺序对字符串进行排序,然后逐字母或类似的搜索。
答案 0 :(得分:6)
您可以将列表namesListB
的元素放入新的Set
(最好是HashSet
)。然后调用namesListA.removeAll(setFromListB);
会更有效,因为ArrayList.removeAll
调用Collection.contains()
的实现在Set
(HashSet
)中比在ArrayList
HashSet.contains()
更有效ArrayList.contains()
namesListA.removeAll(namesListB);
具有恒定的时间效果,而namesListA
具有线性表现。)
无论如何,N = namesListA.length
应该有用,如果M = namesListB.length
没有变化,则2个列表没有共同的元素。
估计时间复杂度(HashSet
,namesListB
):
从namesListA.removeAll(setListB)
创建HashSet
: O(M)
致电List
: O(N * 1)= O(N)
总计: O(M + N)(可以写为O(M),因为M> N,但我不确定)
答案 1 :(得分:2)
为namesListB
中的400 000个名称创建一个集合。然后使用此集删除namesListA
。
List<String> namesListA = new ArrayList<>(/*50 000 strings*/);
List<String> namesListB = new ArrayList<>(/*400 000 strings*/);
Set<String> undesiredNames = new HashSet<>(namesListB);
for (String name : namesListA) {
if (undesiredNames.contains(name)) {
namesListA.remove(name);
}
}
答案 2 :(得分:1)
一种可能性是并行化删除。列表namesListA
和namesListB
可以按起始字符分组;然后可以分组并行地进行删除,并且可以再次连接结果列表。
假设有一些标准拉丁字母,这将导致大约26组可以并行处理。如果4个线程可以并行运行,我预计会有显着的加速。
答案 3 :(得分:1)
我建议使用String
代替String
来存储最大集合的O(1)
,以便了解集合是否包含给定{{1}时间复杂度为O(n)
而不是removeAll(Collection<?> c)
,然后使用String
仅保留第二个集合中不属于List<String> namesListA = new ArrayList<>(/*50 000 strings*/);
Set<String> namesSetB = new HashSet<>(/*400 000 strings*/);
namesListA.removeAll(namesSetB);
的{{1}}:
{{1}}
答案 4 :(得分:1)
这是 O(n * logn)的解决方案。 应该比发布的方法更快。 编辑:如果你不需要确切的元素,我的另一种方法会更快。
1.。)对两个列表进行排序
使用Collections.sort(...)在O(n * logn)中进行有效排序。
2.。与两个迭代器进行比较
在两个列表上获取两个迭代器。然后:
while(leftIterator.hasNext() && rightIterator.hasNext(){
int comparisonResult = leftElement.compare(rightElement);
if (comparisonResult == -1){
leftElement = leftIterator.next();
}
else if (comparisonResult == 1){
rightElement = rightIterator.next();
}
else{
// found it!
return true;
}
}
(抱歉,如果我输入错误,请不要使用IDE)
=&GT;排序在O(i logi + j logj))
=&GT;比较是在O(i + j)
结果表现在等级O(n * logn)中有效。这应该很好用。
答案 5 :(得分:0)
执行removeAll列表可能是一个更好的解决方案,考虑到你有两个变量都有50k和400k大小的列表
namesListA.removeAll(namesListB);
答案 6 :(得分:0)
如果重要的是哪个元素不重要但只有如果那么你可以让集合为你做到这一点。
int sizeA = listA.size();
int sizeB = listB.size();
Set merger = new HashSet((sizeA+sizeB)*someLoadFactor);
merger.addAll(listA);
merger.addAll(listB);
// Sets do not contain duplicates!
if (merger.size() < sizeA + sizeB){
return true;
}
return false;
这在O(i + j)运行如此有效 O(n)!