一、哈希表理论基础
哈希表是根据关键码(key)的值而直接进行访问的数据结构。
一般哈希表都是用来快速判断一个元素是否出现集合里。如果使用枚举法的话,时间复杂度为O(n),而使用哈希表的话则只需要O(1)。
哈希函数通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。
![](https://img-blog.csdnimg.cn/img_convert/75cf79d1f3c463002b326d5e8cfd77ed.png)
哈希碰撞:如果需要取哈希数的值的总数量大于哈希表的长度,就会导致几个数据被映射到哈希表同一个索引下标的位置。那么可以使用两种办法,一种是拉链法,即出现碰撞的部位使用链表按序排放;一种是线性探测法,这种方法要求哈希表全长较大,就是向下寻找空位放入数据。
js当中一般使用map而不使用set。
使用哈希表是一种牺牲空间换时间的做法。
二、242 有效的字母异位词
思路:为两个字符串分别构造长度为26的数组,用每个字符的ascii码顺序来当作键,每次加一,最后比较两个数组。时间复杂度为O(n)。
代码:
var isAnagram = function(s, t) {
// 记住fill这个方法
var sMap = new Array(26).fill(0);
var tMap = new Array(26).fill(0);
var a = 'a';
for (let i=0; i<s.length; i++) {
var index = s.charCodeAt(i) - a.charCodeAt(0);
sMap[index] = sMap[index] ? sMap[index] + 1 : 1;
}
for (let i=0; i<t.length; i++) {
var index = t.charCodeAt(i) - a.charCodeAt(0);
tMap[index] = tMap[index] ? tMap[index] + 1 : 1;
}
// 两个数组不能直接用==来比较
return sMap.toString() == tMap.toString();
};
383 赎金信
题目链接:https://leetcode.cn/problems/ransom-note/
思路:和上题几乎一样,可以用26位数组也可以用map。这里展示的代码用的是map。
代码:
var canConstruct = function(ransomNote, magazine) {
var array = magazine.split('');
var map = new Map();
for (let i=0; i<array.length; i++) {
map.set(array[i], map.has(array[i]) ? map.get(array[i]) + 1 : 1);
}
var note = ransomNote.split('');
for (let i=0; i<note.length; i++) {
if (!map.has(note[i])) {
return false;
}
else {
if (map.get(note[i]) == 1) {
map.delete(note[i]);
}
else {
map.set(note[i], map.get(note[i]) - 1);
}
}
}
return true;
};
49 字母异位词分组
题目链接:https://leetcode.cn/problems/group-anagrams/
思路:将每个词产生的26位数组作为object的key,而将这个词本身添加进value的列表当中。最后返回这个object的所有value。为什么不用map?因为map的键不可以是数组。哈希表的实现是基于地址的,两个所有元素相等但地址不同的数组是不一样的,不会在一个map的键下面。
![](https://img-blog.csdnimg.cn/img_convert/4faf8c4c24c06d71ae70c6cac63faf34.png)
代码:
var groupAnagrams = function(strs) {
const map = new Object();
for (let s of strs) {
const count = new Array(26).fill(0);
for (let c of s) {
count[c.charCodeAt() - 'a'.charCodeAt()]++;
}
map[count] ? map[count].push(s) : map[count] = [s];
}
return Object.values(map);
};
也可以用排序后的字符串当作键。
![](https://img-blog.csdnimg.cn/img_convert/7a9fb463cab8db7bdbebc7b3e2a8b1e3.png)
438 找到字符串中所有字母异位词
题目链接:https://leetcode.cn/problems/find-all-anagrams-in-a-string/
思路:将初始的字典找出,然后利用滑动窗口解题。
三、349 两个数组的交集
思路:创建一个数组的map,再用另一个数组与之比较
代码:
var intersection = function(nums1, nums2) {
var result = [];
var map = new Map();
for (let i=0; i<nums1.length; i++) {
map.set(nums1[i], map.has(nums1[i]) ? map.get(nums1[i]) + 1 : 1);
}
for (let i=0; i<nums2.length; i++) {
if (map.has(nums2[i])) {
// 每次找到之后在map中删掉,以免下次再找到重复
map.delete(nums2[i]);
result.push(nums2[i]);
}
}
return result;
};
350 两个数组的交集II
题目链接:https://leetcode.cn/problems/intersection-of-two-arrays-ii/
思路:与349其实很像,但是这一次不能找到了就将map中对应的值删掉,而是每次减一,直到不能减了再删掉,这样才能让共同出现的次数与其实际情况相同。
代码:
var intersect = function(nums1, nums2) {
var result = [];
var map = new Map();
for (let i=0; i<nums1.length; i++) {
map.set(nums1[i], map.has(nums1[i]) ? map.get(nums1[i]) + 1 : 1);
}
for (let i=0; i<nums2.length; i++) {
if (map.has(nums2[i])) {
result.push(nums2[i]);
if (map.get(nums2[i]) == 1) {
map.delete(nums2[i]);
}
else {
map.set(nums2[i], map.get(nums2[i]) - 1);
}
}
}
return result;
};
四、202 快乐数
思路:用一个history数组记录下目前所有得出的数据,只要曾经出现重复就返回false,出现1就返回true
代码:
var isHappy = function(n) {
var history = [];
var number = n;
while (true) {
var array = number.toString().split('');
var result = 0;
for (let i=0; i<array.length; i++) {
result += array[i] * array[i];
}
if (result == 1) {
return true;
}
if (history.indexOf(result) !== -1) {
return false;
}
else {
history.push(result);
number = result;
}
}
};
五、1 两数之和
思路:依次遍历数组,既然只有一组符合答案的数据,那么可以每次经过的时候都判断是否有target-当前值的这样一个数据存在在map中,如果有的话就返回,没有的话在map中加入[value: key]键值对。
代码:
var twoSum = function(nums, target) {
var map = new Map();
for (let i=0; i<nums.length; i++) {
if (map.has(target - nums[i])) {
return [map.get(target - nums[i]), i];
}
else {
map.set(nums[i], i);
}
}
};
今日学习时长:2h左右
总结:今天438题脑袋转不动先不写了,总体还可以,对map的掌握熟练了一些,下次刷的时候需重点注意438和49。今天学到了map的键不可以是数组,因此有时需要合理使用toString()函数,而且记住fill函数, var array = new Array(26).fill(0)。