我有以下问题:我需要在两个列表中找到相同元素的对,这两个列表是无序的。关于这两个列表的事情是它们“大致相等” - 只有某些元素被一些索引移动,例如(注意,这些对象不是整数,我只是在这个例子中使用整数):
[1,2,3,5,4,8,6,7,10,9]
[1,2,3,4,5,6,7,8,9,10]
我的第一次尝试是迭代两个列表,并根据每个对象的一些唯一键生成两个HashMaps。然后,在第二遍时,我只需从两个地图中拉出元素。这会在空间和时间上产生O(2N)
。
我正在考虑一种不同的方法:我们将保留指向两个列表中当前元素的指针,以及每个列表的当前未匹配集。伪代码将是以下类型:
while(elements to process)
elem1 = list1.get(index1)
elem2 = list2.get(index2)
if(elem1 == elem2){ //do work
... index1++;
index2++;
}
else{
//Move index of the list that has no unamtched elems
if(firstListUnmatched.size() ==0){
//Didn't find it also in the other list so we save for later
if(secondListUnamtched.remove(elem1) != true)
firstListUnmatched.insert(elem1)
index1++
}
else { // same but with other index}
}
以上可能不起作用......我只是想大致了解你对这种方法的看法。基本上,这在每个列表的一侧维护一个散列集,其大小<<问题的大小。对于少量错位元素和小“间隙”,这应该是~O(N)。无论如何,我期待你的回复。
编辑:我不能简单地返回两个对象列表的集合交集,因为我需要对我发现匹配/不匹配的对象执行操作(甚至多个操作)
答案 0 :(得分:1)
我不能简单地返回两个对象列表的集合交集,因为我需要对我发现匹配/不匹配的对象执行操作(甚至多个操作)
您可以维护一组不匹配的对象。这将是空间中的O(M),其中M是任何点处交换元素的最大数量。对于N是元素数的时间,它将是O(N)。
interface Listener<T> {
void matched(T t1);
void onlyIn1(T t1);
void onlyIn2(T t2);
}
public static <T> void compare(List<T> list1, List<T> list2, Listener<T> tListener) {
Set<T> onlyIn1 = new HashSet<T>();
Set<T> onlyIn2 = new HashSet<T>();
for (int i = 0; i < list1.size(); i++) {
T t1 = list1.get(i);
T t2 = list2.get(i);
if (t1.equals(t2)) {
tListener.matched(t1);
continue;
}
if (onlyIn2.remove(t1))
tListener.matched(t1);
else
onlyIn1.add(t1);
if (!onlyIn1.remove(t2))
onlyIn2.add(t2);
}
for (T t1 : onlyIn1)
tListener.onlyIn1(t1);
for (T t2 : onlyIn2)
tListener.onlyIn2(t2);
}
答案 1 :(得分:0)
如果我已正确理解您的问题,您可以使用Collection.retainAll然后迭代已保留的集合并执行您必须执行的操作。
list2.retainAll(list1);
答案 2 :(得分:0)
基于地图的所有方法最多都是O(n log(n)),因为创建地图是插入排序。效果是对两者进行插入排序,然后比较它们,这样就可以得到它。
如果列表几乎排序为开头,则排序步骤不应该与平均情况一样长,并且将与O(n log(n))一起缩放,因此只需对两者进行排序并进行比较。这使您可以根据需要单步执行匹配或不匹配的项目。