Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在比较两个列表中的元素时,如何避免O(N^2)?_Java_Algorithm_List - Fatal编程技术网

Java 在比较两个列表中的元素时,如何避免O(N^2)?

Java 在比较两个列表中的元素时,如何避免O(N^2)?,java,algorithm,list,Java,Algorithm,List,我有两个相同对象类型的列表 List A [ foo, bar, moo, woo, pee ] List B [ bar, woo ] 我想比较这两个列表,如果名称匹配, 将其属性设置为true 比如说, if(ListA[1].name.equals(ListB[0].name)) { //match name 'bar' and 'bar' ListA[1].hasSameName = true; } 差不多吧 我能写出O(N^2)解 for(Talent checkedTa

我有两个相同对象类型的列表

List A [ foo, bar, moo, woo, pee ]

List B [ bar, woo ]
我想比较这两个列表,如果名称匹配, 将其属性设置为true

比如说,

if(ListA[1].name.equals(ListB[0].name)) { //match name 'bar' and 'bar'
    ListA[1].hasSameName = true;
}
差不多吧

我能写出O(N^2)解

for(Talent checkedTalent : ListA) {
    for(Talent filteredTalent : ListB) {
        if( checkedTalent.Id.equals(filteredTalent.Id) ) {
            filteredTalent.isSelected = true;   
        }
    }
}
这能以更有效的方式完成吗?

请注意,O(n2)解决方案具有时间复杂性,因为对于
ListA
中的每个元素,必须检查所有
ListB
(再次)。如果您可以从
ListA
中对当前元素在
ListB
上进行O(1)查找,则可以减少到O(n)。可以使用的一种数据结构是
映射

因此,如果您从一个列表中构建一个
映射
,然后遍历另一个列表,在
映射
中查找每个元素以查看是否存在匹配,您可以将总体时间复杂度降低到O(n)-以O(n)空间为代价

例如:

Map<String, Talent> map = new HashMap<String, Talent>();

for(Talent t : ListA)
{
    t.put(t.id, t);
}

for(Talent t : ListB)
{
    if(map.containsKey(t.id))
    {
        t.isSelected = true;
    }
}
Map Map=newhashmap();
对于(人才t:ListA)
{
t、 put(t.id,t);
}
对于(人才t:ListB)
{
if(地图容器(t.id))
{
t、 isSelected=true;
}
}
然后排序(2*(n log n)),然后沿着每个列表(2*n)走一走。

使用哈希作为O(n)解决方案(假设高效的哈希实现):

Set id=newhashset(ListA.size());
对于(人才盘点人才:ListA){
添加(checkedTalent.Id);
}
对于(人才筛选人才:列表B){
if(Id.contains(filteredTalent.Id)){
FilteredTalence.isSelected=true;
}
}

关于如何更有效地实现这一点的一些启示,请阅读如何实现SQL联接,即使用b树索引的嵌套循环联接(对一个进行排序并对另一个中的每个元素进行二进制搜索)、a或a。相同的概念。

您可以从第一个列表创建一个集合:

Set mySet = new HashSet(listA);
现在,在列表B上循环:

for(Object foo : listB)
    if(mySet.contains(foo))
        foo.isSelected = true

我想这是O(n*lg n),但我不会提供证据。:)

快速但愚蠢:排序和比较。顺序重要吗?会有欺骗吗?因为在这些情况下,琐碎的事情甚至可能不是真的。如果不重要,也没有重复,我建议使用集合而不是列表。@amit:不会有重复的值,顺序也不重要。然后我投票赞成建议的哈希解决方案,但我仍然认为(至少在可读性方面)使用集合比列表更合适(除非是关键性能问题,并且无法承担插入开销)@amit:我也同意,使用Set似乎更好。可以是
Set
,不必是,正如上面的例子所示。总体时间复杂度是相同的-但是,我承认使用
Set
的答案更干净。与
HashMap
不同,没有
add()
方法。您必须使用
put(t.id,null)
然后检查
map.keySet().containsKey(t.id)
。可能你想要的是
而不是
映射
。啊!这就是我在睡觉的时候闲逛得到的东西:/Sorry@John,thanking@amit,@aroth。现在修复了它。HashSet有一个构造函数,它接受任何集合作为参数,这将使你不必实现第一个循环(尽管你仍然要承担费用)。哦-我看到你将每个天赋映射到一个Id。我没有意识到。别提这个评论。:)
for(Object foo : listB)
    if(mySet.contains(foo))
        foo.isSelected = true