很久没有更新文档了
今天带一个leetcode常见的字符串算法,主要用于求字符串出现的次数和相同公共前缀
具体看下面的代码,最后会做出解释
class TrieNode {
constructor() {
this.pass = 0
this.end = 0
this.nexts = new Array(26)
}
}
class Trie {
constructor() {
this.root = new TrieNode()
}
inset(word) {
if (!word) {
return
}
let node = this.root;
node.pass++
let index = 0
for(let i = 0; i < word.length; i++) {
index = word[i].charCodeAt() - 'a'.charCodeAt()
if (!(node.nexts[index])) {
node.nexts[index] = new TrieNode()
}
node = node.nexts[index]
node.pass++
}
node.end++
}
// 查找字符串出现过几次
search(word) {
if (!word) {
return 0;
}
let node = this.root;
let index = 0
for(let i = 0; i < word.length; i++) {
index = word[i].charCodeAt() - 'a'.charCodeAt()
if (!(node.nexts[index])) {
return 0
}
node = node.nexts[index]
}
return node.end
}
// 查询字符串前缀出现了几次
searchPer(word) {
if (!word) {
return 0
}
let node = this.root;
let index = 0
for(let i = 0; i < word.length; i++) {
index = word[i].charCodeAt() - 'a'.charCodeAt()
if (!(node.nexts[index])) {
return 0
}
node = node.nexts[index]
}
return node.pass
}
// 删除节点
delete(word) {
// 判断节点有没有插入过
if (this.search(word) === 0) {
return 0;
}
let node = this.root;
node.pass--
let index = 0
for(let i = 0; i < word.length; i++) {
index = word[i].charCodeAt() - 'a'.charCodeAt()
if (--(node.nexts[index].pass) == 0) {
node.nexts[index] = null
return;
}
node = node.nexts[index]
}
node.end--
}
}
const trieNodes = new Trie()
let arrMapList = ["abc", "ab", "cd", "dc", "a"]
arrMapList.forEach(item => {
trieNodes.inset(item)
})
TrieNode是数据结构类
- pass表示节点的路径次数
- end表示一个字符串结尾的次数
- nexts下级节点(abc, ab, a) 头部都是a,那 abc, ab, a 都存储在一个nexts中
Trie 算法实现类
实例化类的时候就初始化数据结构
inset函数用于将所有字符串插入到nexts中
重点在这一块代码
index = word[i].charCodeAt() - 'a'.charCodeAt()
if (!(node.nexts[index])) {
node.nexts[index] = new TrieNode()
}
node = node.nexts[index]
node.pass++
// 字符串都是a-z
// 那只要每一个字符串 Unicode码 - a的Unicode码,就能得出存储位置
// 判断!(node.nexts[index] 这个字母有没有没存储过,如果没有就构建
// node = node.nexts[index] 指针位移到下一个节点
// 节点pass++
直接把代码复制到编辑器里面,调试一边就懂了,很简单。