java中HashMap.containsValue()的时间复杂度是多少?
Posted
技术标签:
【中文标题】java中HashMap.containsValue()的时间复杂度是多少?【英文标题】:What is the time complexity of HashMap.containsValue() in java? 【发布时间】:2013-05-21 09:02:19 【问题描述】:在O(n)
时间复杂度中给了我一个要解决的问题:
“给定一个数字列表和数字 x。查找列表中是否有 2 个数字加起来为 x?”
这是我的解决方案:
public class SumMatchResult
public static void main(String[] args)
int[] numberList = 6,1,8,7,4,6;
int requiredSum = 8;
boolean isSumPresent = checkSumPresentHash(numberList,requiredSum);
if(isSumPresent)
System.out.println("Numbers exist");
else
System.out.println("Numbers donot exist");
private static boolean checkSumPresentHash(int[] numberList, int requiredSum)
Map<Integer, Integer> m = new HashMap<Integer,Integer>();
int count = 0;
for(int i=0;i<numberList.length;i++)
m.put(i, numberList[i]);
for(int i=0;i<numberList.length;i++)
if(m.containsValue(requiredSum - numberList[i]))
count++;
if(count>1)
return true;
return false;
我使用HashMap.containsValue()
而不是使用HashSet.contains()
,它肯定具有O(1)
的复杂性,因为我必须考虑我的输入可能包含相同值的情况。例如,在上述情况下,我可以有一组输入值3,6,4,4,7
与sum 8
匹配,它应该返回true
。
我上述解决方案的时间复杂度取决于HashMap.containsValue()
方法的复杂度。请阐明containsValue()
方法的时间复杂度,并建议我在时间复杂度方面是否有上述问题的更好解决方案。谢谢。
【问题讨论】:
也许你应该使用Set
而不是Map
。
我很想知道有一种算法可以在 O(n) 时间内解决这个问题。我不确定这是否可能。
保持一个单独的HashMap
与第一个值作为他的键怎么样?这样您就可以立即知道 (O(1)
) 是否存在值。这是O(2n)
空间,但嘿,这很值得。
@JBNizet 我上次看到它已经有很长时间了,但这闻起来像是背包问题的(非常)简化版本。动态编程在这里应该有所帮助。
@Bohemian 不,它是关于containsValue()
,这是复杂性的根本区别。
【参考方案1】:
要回答标题中的问题 - 正如其他人所提到的,containsValue
是 O(n),因为没有密钥它不知道它在哪里,并且算法必须遍历存储在地图。
要回答问题正文中的问题 - 关于如何解决问题 - 只需考虑您是否真的需要一张通用地图,该地图可以计算您看到每个数字的实例数。我的意思是,唯一你会关心一个数字是否不止一次出现的时候是它的 x/2,对吧?这对我来说就像一个角落里的箱子。只需添加一个检查该极端情况的测试——比如在你的集合构造循环中嵌入if (numberList[i] == requiredSum/2) half++
,然后在它之后嵌入if (requiredSum % 2 == 0 && half == 2) return true
(参见下面的其他变体)。
然后你可以遍历集合并为每个项目检查 requiredSum-item
是否也出现在集合中。
总结(尽可能提前退出):
Set<Integer> seen = new HashSet<Integer>();
boolean halfSeen = false;
for (int num : numberList)
if (num == requiredSum/2 && requiredSum % 2 == 0)
if (halfSeen) return true;
halfSeen = true;
else
seen.add(num);
for (int num : seen)
if (seen.contains(requiredSum - num)) return true;
return false;
【讨论】:
+1 关于角盒的好点(if (numberList[i] == requiredSum/2)
)。很棒的整体解决方案!
@Oak :非常感谢您的解决方案。不过稍微修正一下,seen.add(num) 应该在 else 部分,否则,即使只有一个 num ==requiredSum/2,它也会被添加到集合中,并且下一个循环返回 true,这是错误的。
@VishnuVedula 好点,已修复。此更改还需要将除以二的检查移动到封闭的if
,因为如果requiredSum
是7,那么我们确实希望在seen
中保留3。【参考方案2】:
HashMap 本质上是一个键值存储,它可以访问它的键,复杂度为 O(1)。然而,检查一个值,HashMap 只能检查所有值并查看它们是否等于您正在搜索的值。因此,复杂度为 O(n),其中 n 为 HashMap 中的元素个数。
另外一点:您在其装箱类型 (Integer) 的集合中查找原始值 (int)。这意味着每次您在 HashMap 上调用方法时,Java 都需要将原始值装箱:http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html
【讨论】:
以后一定会记住装箱和拆箱的。谢谢你:)【参考方案3】:HashMap.containsValue 复杂度为 O(n)。但是 n 不完全是映射大小,而是哈希表大小,因为即使映射大小 = 0, containsValue 也会遍历所有表元素。 假设我们创建了一个初始容量 = 1024 的空映射。 containsValue 必须遍历 1024 个元素的哈希表数组:
public boolean containsValue(Object value)
if (value == null)
return containsNullValue();
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
【讨论】:
【参考方案4】:HashMap
中没有任何值标记的索引,因此,要使用containsValue()
查找值,您必须遍历HashMap
的所有值。
请注意,这里的复杂度O(n)
是 HashMap 中值的数量,不是我们通常用来表示其复杂度的键/大小。
【讨论】:
以上是关于java中HashMap.containsValue()的时间复杂度是多少?的主要内容,如果未能解决你的问题,请参考以下文章