哈希表
- 定义:根据关键码的形式而直接进行访问的数据结构
- 应用:javascript 中的Object、Set、WeakSet、Map、WeakMap 都是哈希结构。
- 用途:快速判断一个元素是否出现在集合里。
Set、WeakSet
Set类似于数组,但是元素的值都是唯一的,没有重复的值。
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
- WeakSet 的成员只能是对象,而不能是其他类型的值。
- WeakSet 中的对象都是弱引用,ES6 规定 WeakSet 不可遍历
Map、 WeakMap
-
Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。 -
WeakMap与Map的区别有两点。 首先,WeakMap只接受对象(null除外)和 Symbol 值作为键名,不接受其他类型的值作为键名。
其次,WeakMap的键名所指向的对象,不计入垃圾回收机制。
习题
242.有效的字母异位词
思路: 字母为key, 出现的次数为value,判断后比较
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
if(s.length !== t.length) return false
let hash1 = {}
let hash2 = {}
for(let i = 0;i<s.length;i++){
hash1[s[i]] = hash1[s[i]] === undefined ? 0: ++hash1[s[i]]
hash2[t[i]] = hash2[t[i]]=== undefined ? 0: ++hash2[t[i]]
}
let same = true
for(let i in hash1){
if(hash1[i] !=hash2[i]){
same = false
break
}
}
return same
};
349. 两个数组的交集
思路:使用Set数据结构不包含重复值的特点可以很简单做出来
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
return Array.from(new Set(nums1.filter(item=>nums2.includes(item))))
};
202. 快乐数
重点在于理解题干中说到的无限循环,即每个数的平方和会出现相同的数,然后无限循环下去
思路: 存储每次的平方和,当平方和出现过或者等于1时,不再继续计算
/**
* @param {number} n
* @return {boolean}
*/
const getSquareSum = (num)=>{
const arr = String(num).split('')
let sum = 0
arr.forEach(item=>{
sum += Number(item)* Number(item)
})
return sum
}
var isHappy = function(n) {
const sumArr = []
let squareSum = n
let result = Boolean(squareSum === 1)
while(squareSum != 1){
squareSum = getSquareSum(squareSum)
if(squareSum === 1){
result = true
}
if(sumArr.indexOf(squareSum) > -1){
return false
}else{
sumArr.push(squareSum)
}
}
return result
};
疑惑: Set.has 和 数组 indexOf哪种更高效呢
1. 两数之和
思路: 判断一个元素是否出现过!
[2,7,11,15] target = 9,遍历2的时候查看9-2 = 7,7是否出现过,遍历7的时候查看2是否出现过
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
const map = new Map()
let res = []
for (let i = 0; i < nums.length; i++) {
const diff = target - nums[i]
if (map.has(diff)) {
res = [map.get(diff), i]
return res;
} else {
map.set(nums[i], i)
}
}
return res
};
附: forEach 中不能使用break,使用return只是跳出本次循环,后面的循环还会执行,所以这里使用for
总结
哈希表消耗了内存空间,减少了运行时间,这就是「空间换时间」。
很多涉及到「两个变量」的题目,都可以枚举其中一个变量,把它当成常量看待,从而转换成「一个变量」的问题。
代码实现时,通常来说枚举右,寻找左 是更加好写的。