持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
[面试题 17.17. 多次搜索](leetcode.cn/problems/th…)
给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索。输出smalls中的字符串在big里出现的所有位置positions,其中positions[i]为smalls[i]出现的所有位置。
「示例1:」
输入:
big = "mississippi"
smalls = ["is","ppi","hi","sis","i","ssippi"]
输出: [[1,4],[8],[],[3],[1,4,7,10],[5]]
「提示:」
0 <= len(big) <= 1000
0 <= len(smalls[i]) <= 1000
smalls的总字符数不会超过 100000。
你可以认为smalls中没有重复字符串。
所有出现的字符均为英文小写字母。
解题思路
1.对smalls所有字符串建立Trie,在节点中保存是否是字符串尾部isword,以及在smalls数组中的位置index
2.遍历big字符串,如果查找到节点为为字符串尾部isword,则根据索引index 添加到result数组中
代码实现
/*
* trie 节点
*/
function TreeNode(val) {
this.children = {};
this.isword = false; //标记是否是字符串结尾
this.index =-1; //标记单词在数组中的位置
}
var Trie = function () {
this.root = new TreeNode();
this.count = 0; //记录字符串的个数,用来给字符串节点标记次序
}
/**
* Trie 树的插入
* */
Trie.prototype.insert= function (word) {
if (!word) return;
let node = this.root;
for (let i=0 ;i <word.length;i++){
if (!node.children[word[i]]){
node.children[word[i]] = new TreeNode();
}
node = node.children[word[i]];
}
node.index = this.count;
node.isword = true;
this.count++;
}
/**
* Trie 树的字符串搜索
* */
Trie.prototype.search=function (word) {
if (!word) return false;
let node = this.root;
for (let i=0;i<word.length;i++){
if (!node.children[word[i]]){
node = node.children[word[i]];
}else
{
return false;
}
}
return node.isword;
}
/**
* Trie 查找是否有已prefix开头的字符串
* */
Trie.prototype.startsWith = function(prefix) {
if (!prefix)return false;
let node = this.root;
for (let i =0;i <prefix.length;i++){
if (node.children[prefix[i]]){
node = node.children[prefix[i]];
}else
{
return false;
}
}
return true;
};
/**
* @param {string} big
* @param {string[]} smalls
* @return {number[][]}
*/
var multiSearch = function(big, smalls) {
let result = Array(smalls.length).fill(0).map(()=>[]); //预生成数组
let maxLength = Math.max(...smalls.map(small=> small.length)); //计算smalls中字符串的最大长度
let trie = new Trie(); //预建trie树
//将smalls 字符串插入树中
for (let i=0;i< smalls.length;i++){
trie.insert(smalls[i]);
}
for (let i=0;i<big.length;i++){
if(!trie.startsWith(big[i])) continue; //查找是否以 big[i] 开头的字符串,没有则跳过本次执行
let str = big.slice(i,i+maxLength);
let node = trie.root;
for (let j=0;j<str.length;j++)
{
let jchar = str[j];
if (!node.children[jchar]){
break;
}
node = node.children[jchar];
if (node.isword){
result[node.index].push(i);
}
}
}
return result;
};
如果你对这道题目还有疑问的话,可以在评论区进行留言;