转载 https://blog.csdn.net/u013468917/article/details/51362156
问题源自于leetcode上的一道题:
twoSum:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
这道题 一般的解决方法是的一个比较容易想到的解决方法是:进行两次遍历,但是复杂度会达到O(n2)。一个比较好的解决方法是使用HashMap复杂度可以降低到O(n)。一开始我根据类似用HashMap的思想,使用ArrayList来做,代码如下:
-
public
int[] twoSum(
int[] nums,
int target) {
-
ArrayList<Integer> list =
new ArrayList<Integer>();
-
-
for(
int i=
0; i<nums.length; i++){
-
if(list.contains(target-nums[i])){
-
return
new
int[]{list.indexOf(target-nums[i]), i};
-
}
-
list.add(nums[i]);
-
}
-
return
null;
-
}
结果发现效率和笨方法差不多,运行时间根本没有得到改善,网站上的测试用例的运行时间是56ms,仅beat百分十几。后来用HashMap来做:
-
public
int[] twoSum(
int[] nums,
int target) {
-
HashMap<Integer, Integer> map =
new HashMap<Integer, Integer>();
-
for(
int i=
0; i<nums.length; i++){
-
if(map.containsKey(target-nums[i])){
-
return
new
int[]{map.get(target-nums[i]), i};
-
}
-
map.put(nums[i], i);
-
}
-
return
null;
-
}
效率得到明显改善:6ms,这两段代码唯一的不同之处就是一个用ArrayList存储元素,另一个用HashMap。效率相差了近10倍!
为什么会有这么大的差距呢:
原因时ArrayList使用的是数组来存储元素,而HashMap使用哈希表来存储元素。在上面两段代码中,效率拉开差距的是在contains和containsKey方法上。
ArrayList的contains方法是通过调用自己的index of方法来判断的:
-
public int indexOf(Object o) {
-
if (o ==
null) {
-
for (
int i =
0; i < size; i++)
-
if (elementData[i]==
null)
-
return i;
-
}
else {
-
for (
int i =
0; i < size; i++)
-
if (o.equals(elementData[i]))
-
return i;
-
}
-
return -
1;
-
}
可以看到,在源码中,index方法把整个数组顺序遍历了一遍,这种查找方法无疑是效率最低的。
在HashMap,key被存储到hash表中,查找时是在hash表上进行查找,关于hash表的查找方法很简单这里就不赘述了。
-
public boolean containsKey(Object key) {
-
return getNode(hash(key), key) !=
null;
-
}
-
final Node<K,V> getNode(int hash, Object key) {
-
Node<K,V>[] tab; Node<K,V> first, e;
int n; K k;
-
if ((tab = table) !=
null && (n = tab.length) >
0 &&
-
(first = tab[(n -
1) & hash]) !=
null) {
-
if (first.hash == hash &&
// always check first node
-
((k = first.key) == key || (key !=
null && key.equals(k))))
-
return first;
-
if ((e = first.next) !=
null) {
-
if (first
instanceof TreeNode)
-
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
-
do {
-
if (e.hash == hash &&
-
((k = e.key) == key || (key !=
null && key.equals(k))))
-
return e;
-
}
while ((e = e.next) !=
null);
-
}
-
}
-
return
null;
-
}
总之,如果要用contains方法,用HashMap来代替要远远快于ArrayList,如果要遍历的话还是用ArrayList吧。