给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。java
你能够假设每种输入只会对应一个答案。可是,你不能重复利用这个数组中一样的元素。node
示例:数组
给定 nums = [2, 7, 11, 15], target = 9 由于 nums[0] + nums[1] = 2 + 7 = 9 因此返回 [0, 1]
官方解答:
public int[] twoSum(int[] nums, int target) { Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { map.put(nums[i], i); } for (int i = 0; i < nums.length; i++) { int complement = target - nums[i]; if (map.containsKey(complement) && map.get(complement) != i) { return new int[] { i, map.get(complement) }; } } throw new IllegalArgumentException("No two sum solution"); }
官方这样的作法时间复杂度是o(n),可是for循环里带containKey怎么会是o(n)呢?指针
原来map.containKey()的复杂度能够看作o(1):code
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); } }
1. 指针first指向那一行数组的引用(那一行数组是经过table下标范围n-1和key的hash值计算出来的),若命中,则经过下标访问数组,时间复杂度为O(1)
2. 若是没有直接命中(key进行hash时,产生相同的位运算值),存储方式变为红黑树,那么遍历树的时间复杂度为O(n)。
blog
另外,由于hashMap以key存hash,value是根据key所得。因此containValue()的时间复杂度为O(n),和containKey()不一样。get