其他分享
首页 > 其他分享> > 745. 前缀和后缀搜索

745. 前缀和后缀搜索

作者:互联网

题目描述

设计一个包含一些单词的特殊词典,并能够通过前缀和后缀来检索单词。

实现 WordFilter 类:

提示:

示例:

输入
["WordFilter","f"]
[[["apple","apply","ale"]],["app","le"]]
输出
[null, 1]

 

解题思路:

1.字典树

 

补充:一开始仅将index的类型设为一个数,认为每次加入新单词时,更新 index  为当前单词下标即可得到最大下标。但要注意的是,有可能出现前缀匹配的单词索引与后缀匹配的单词索引不一致的情况,而这样做得不到正确的最大下标。因此改为Array类型。

 

代码实现:

/**
 * @param {string[]} words
 */
var WordFilter = function(words) {
    function Node(list,map){
        this.index = list;
        this.children = map;
    }
    this.pref_root = new Map(); //前缀树
    this.suff_root = new Map(); //后缀树
    for(let i=0;i<words.length;i++){
        let len = words[i].length;
        let pref_cur = this.pref_root;
        let suff_cur = this.suff_root;
        for(let j=0;j<len;j++){
            let letter = words[i][j];

            
            if(pref_cur.has(letter)){//前缀已在字典中时,将当前单词索引加入该节点的index,表示当前单词包含此前缀
                let node = pref_cur.get(letter);
                node.index.push(i);
                pref_cur = node.children;
            }else{//字典中不存在该前缀则创建新的Node
                let node = new Node(new Array(),new Map());
                node.index.push(i);
                pref_cur.set(letter,node);
                pref_cur = node.children;
            }
        }
        for(let j=len-1;j>=0;j--){
            let letter = words[i][j];
            if(suff_cur.has(letter)){
                let node = suff_cur.get(letter);
                node.index.push(i);
                suff_cur = node.children;
            }else{
                let node = new Node(new Array(),new Map());
                node.index.push(i);
                suff_cur.set(letter,node);
                suff_cur = node.children;
            }
        }
    }
};

/** 
 * @param {string} pref 
 * @param {string} suff
 * @return {number}
 */
WordFilter.prototype.f = function(pref, suff) {
    function search(str,root){
        let cur = root;
        let i=0;
        while(i<str.length){
            if(cur.has(str[i])){
                if(i==str.length-1){//当搜索到最后一个字符,直接返回index列表,表示包含该前缀的所有单词索引
                    return cur.get(str[i]).index;
                }else{
                    cur = cur.get(str[i]).children;
                    i++;
                }
            }else{
                return null;
            }
        }
    }
    let list1 = search(pref,this.pref_root);
    let list2 = search(suff.split('').reverse().join(''),this.suff_root);//注意,要将后缀字符串翻转进行搜索

    //当其中一个列表为空,表示前缀或后缀在字典树中匹配不到
    if(list1==null||list2==null){
        return -1;
    }else{
        //从后往前进行搜索,找到两者相同的索引,表示该单词同时满足题目的前缀和后缀
        for(let i=list1.length-1,j=list2.length-1;i>=0&&j>=0;){
            if(list1[i]==list2[j]){
                return list1[i];
            }else if(list1[i]>list2[j]){
                i--;
            }else{
                j--;
            }
        }
        return -1;
    }
};

/**
 * Your WordFilter object will be instantiated and called as such:
 * var obj = new WordFilter(words)
 * var param_1 = obj.f(pref,suff)
 */

 

示例中的字典树如下

 

 

 

 

  搜索前缀 "app" ,定位到 pref_root 中第三层字符 " p ",提取出index=[0,1];搜索后缀"le",定位到suff_root中第二层字符 " l ",提取出Index=[0,2]。因此两个列表的相同最大下标为:0。

 

 

2.暴力解法

  枚举出每个单词前缀和后缀组合的可能性,前缀与后缀用特殊符号连接,连接后的字符串作为键,对应的下标作为值保存到哈希表中。当后面单词的前后缀组合在前面出现过,则更新该组合的下标。由于单词是从前往后遍历的,因此可以保证更新后的下标必然是最大下标。

 

代码实现:

/**
 * @param {string[]} words
 */
var WordFilter = function(words) {
    this.dict = new Map();
    let index = 0;
    for(const word of words){
        let len = word.length;
        let pref = '';
        for(let i=0;i<len;i++){
            pref += word[i];
            let suff = '';
            for(let j=len-1;j>=0;j--){
                suff = word[j] + suff;//从后往前遍历时,新字符应该添加到旧后缀的前面
                this.dict.set(pref+'+'+suff,index);
            }
        }
        index++;
    }
};

/** 
 * @param {string} pref 
 * @param {string} suff
 * @return {number}
 */
WordFilter.prototype.f = function(pref, suff) {
    let str = pref+'+'+suff;
    if(this.dict.has(str)){
        return this.dict.get(str);
    }else{
        return -1;
    }
};

/**
 * Your WordFilter object will be instantiated and called as such:
 * var obj = new WordFilter(words)
 * var param_1 = obj.f(pref,suff)
 */

 

以apple为例,所有的前后缀组合为("+"号后面字符串为后缀):

 

 

 

标签:index,suff,745,后缀,pref,单词,前缀
来源: https://www.cnblogs.com/evil-shark/p/16477275.html