给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
要求复杂度低于O(n^2),那么双重for循环就不能使用了。
使用 HashMap 可完美实现。代码如下:
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hashtable = new HashMap<>(nums.length - 1);
for (int i = 0; i < nums.length; i++) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
知识点记录
HashMap 的特点
几种常见的数据结构有:顺序结构、链表结构、hash结构和树状结构。HashMap是 key-value 形式存储。哈希表将 key 的 Hash 值映射到内存地址,即根据 key 获取对应的值,并将其存储到内存地址。也就是说 HashMap 是根据 key 的 Hash 值来决定对应值的存储位置。通过这种索引方式,HashMap 获取数据的速度会非常快。
例如,存储键值对(x,“aa”)时,哈希表会通过哈希函数 f(x) 得到 Hash 值("aa"的实现存储位置)。
但也会有新的问题。如果再来一个 (y,“bb”),哈希函数 f(y) 的 Hash 值跟之前 f(x) 是一样的,这样两个对象的存储地址就冲突了,这种现象就被称为哈希冲突。那么哈希表是怎么解决的呢?方式有很多,比如,开放定址法、再哈希函数法和链地址法。
开放定址法很简单,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把 key 存放到冲突位置后面的空位置上去。这种方法存在着很多缺点,例如,查找、扩容等,所以不建议作为解决哈希冲突的首选。
再哈希法顾名思义就是在同义词产生地址冲突时再计算另一个哈希函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但却增加了计算时间。如果我们不考虑添加元素的时间成本,且对查询元素的要求极高,就可以考虑使用这种算法设计。
**HashMap 则是综合考虑了所有因素,采用链地址法解决哈希冲突问题。**这种方法是采用了数组(哈希表)+ 链表的数据结构,当发生哈希冲突时,就用一个链表结构存储相同 Hash 值的数据。
什么是HashCode
Hash 值就是 HashCode。HashCode的产生上面已经说了——通过key生成。
HashMap的初始容量一般设置2的整数幂,原因?
2的幂次方减1后每一位都是1,让数组每一个位置都能添加到元素。 例如十进制8,对应二进制1000,减1是0111,这样在&hash值使数组每个位置都是可以添加到元素的,如果有一个位置为0,那么无论hash值是多少那一位总是0,例如0101,&hash后第二位总是0,也就是说数组中下标为2的位置总是空的。 如果初始化大小设置的不是2的幂次方,hashmap也会调整到比初始化值大且最近的一个2的幂作为capacity。
简单说就是减少哈希冲突,均匀分布元素。