哈希表
- 若关键字为k,则其值存放在f(k)的存储位置上
- 对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2),这种现象称为哈希冲突
哈希冲突处理
- 开放定址法: 产生冲突之后去寻找下一个空闲的空间
- 再哈希法:产生冲突之后再进行哈希,直到没有冲突
- 建立公共溢出区:将冲突的元素放入公共溢出区
- 拉链法:冲突的元素位置处理成链表往下接
LeetCode肝题
-
- 设计哈希集合
// ?
var MyHashSet = function() {
this.data = {}
};
MyHashSet.prototype.add = function(key) {
this.data[key] = true
};
MyHashSet.prototype.remove = function(key) {
this.data[key] = false
};
MyHashSet.prototype.contains = function(key) {
return !!this.data[key]
};
-
- 设计哈希映射
// ??
var MyHashMap = function() {
this.data = {}
};
MyHashMap.prototype.put = function(key, value) {
this.data[key] = value
};
MyHashMap.prototype.get = function(key) {
return this.data[key] == undefined ? -1 : this.data[key]
};
MyHashMap.prototype.remove = function(key) {
this.data[key] = -1
};
- 面试题 16.25. LRU 缓存
// 使用Map结构简单实现
var LRUCache = function(capacity) {
this.limit = capacity
this.data = new Map()
};
LRUCache.prototype.get = function(key) {
const flag = this.data.has(key)
if (!flag) return -1
const value = this.data.get(key)
this.data.delete(key)
this.data.set(key, value)
return value
};
LRUCache.prototype.put = function(key, value) {
const flag = this.data.has(key)
if (!flag) {
if (this.data.size == this.limit) {
const first = this.data.keys().next().value
this.data.delete(first)
// this.data.delete([...this.data][0][0])
}
} else this.data.delete(key)
this.data.set(key, value)
};
-
- TinyURL 的加密与解密
// 做一个时间戳对网址的映射即可(注释为骚操作)
let data = new Map()
var encode = function(longUrl) {
const s = new Date().getTime
data.set(s, longUrl)
return s
// return longUrl
};
/**
* Decodes a shortened URL to its original URL.
*
* @param {string} shortUrl
* @return {string}
*/
var decode = function(shortUrl) {
return data.get(shortUrl)
// return shortUrl
};
-
- 重复的DNA序列
// 遍历字符串,每次截取10位放入map中,如果没有出现过记录为1,出现过的话将值+1
var findRepeatedDnaSequences = function(s) {
if (s.length < 11) return [];
let obj = {}, ans = []
for(let i = 0; i < s.length - 9; i++) {
let str = s.slice(i, 10 + i)
obj[str] ? obj[str] += 1 : obj[str] = 1
}
for(let item of Object.keys(obj)) {
if (obj[item] > 1) ans.push(item)
}
return ans
};
-
- 最大单词长度乘积
// 暴力解法判断哪是否有字母重复
var isRepeat = function(str1, str2) {
for(let i of str1) {
if (str2.includes(i)) return true
}
return false
}
var maxProduct = function(words) {
let ans = 0
for(let i = 0; i < words.length; i++) {
for(let j = i + 1; j < words.length; j++) {
if (isRepeat(words[i], words[j])) continue
ans = Math.max(ans, words[i].length * words[j].length)
}
}
return ans
};
-
- 搜索二维矩阵 II
// 这种矩阵有两个特殊点,右上角和左下角,从右上角开始搜索,如果比target大则到下一行,比target小则到前一列
var searchMatrix = function(matrix, target) {
let i = 0, j = matrix[0].length - 1
while(i < matrix.length && j >= 0) {
if (target == matrix[i][j]) return true
if (target > matrix[i][j]) i++
else j--
}
return false
};
-
- 在二叉树中分配硬币
// 赋予递归函数一个明确的意义:寻找当前节点需要拿入/拿出的硬币数量
// 等于root.val - 1 加上左子树需要拿入/拿出的硬币数量加上右子树需要拿入/拿出的硬币数量
var distributeCoins = function(root) {
var getResult = function(root) {
if (!root) return 0
let l = getResult(root.left)
let r = getResult(root.right)
ans += Math.abs(l)
ans += Math.abs(r)
return root.val - 1 + l + r
}
let ans = 0
getResult(root)
return ans
};
9.430. 扁平化多级双向链表
// 方法一:栈加迭代
var flatten = function(head) {
let p = head, q = []
while(p) {
// 当到子链表最后一个节点,从q中取出节点接上,指针继续往后走
if(!p.next && !p.child && q.length) {
let a = q.pop()
p.next = a
a.prev = p
p = p.next
continue
}
// 没有子节点指针往后走
if (!p.child) {
p = p.next
continue
}
// 处理有子节点的情况
if (p.next) q.push(p.next)
p.next = p.child
p.next.prev = p
p.child = null
p = p.next
}
return head
};
// 方法二:递归
// 赋予递归函数一个明确的意义:将链表中的child节点添加到当前节点后面
var flatten = function(head) {
let p = head, q
while(p) {
// 如果有子节点,递归处理子节点,将子节点接到p的后面,将指针移动到子链表的最后一个节点与q接上
if(p.child) {
q = p.next
p.next = flatten(p.child)
p.child = null
p.next.prev = p
while(p.next) p = p.next
p.next = q
if (q) q.prev = p
}
p = p.next
}
return head
};
-
- 二叉树中所有距离为 K 的结点
// 首先找到目标节点,过程中给经过的节点加上parent属性,方便回溯
// 从目标节点出发,相当于从三个方向left、right、parent找距离为k的节点,每经过一个节点把路径记录到path里,防止重复
var distanceK = function(root, target, k) {
let ans = [], targetRoot, path = {}
let findTarget = (root) => {
if (!root) return
if (root.val == target.val) {
targetRoot = root
return
}
if (root.left) {
root.left.parent = root
findTarget(root.left)
}
if (root.right) {
root.right.parent = root
findTarget(root.right)
}
}
findTarget(root)
let findPath = (root, k) => {
if (!root) return
if (!path[root.val] && k == 0) ans.push(root.val)
path[root.val] = true
findPath(root.left, k - 1)
findPath(root.right, k - 1)
}
findPath(targetRoot, k)
while(targetRoot.parent && k) {
findPath(targetRoot.parent, --k)
targetRoot = targetRoot.parent
}
return ans
};