fucking-algorithm icon indicating copy to clipboard operation
fucking-algorithm copied to clipboard

前缀树算法模板秒杀五道算法题 :: labuladong的算法小抄

Open labuladong opened this issue 3 years ago • 16 comments

文章链接点这里:前缀树算法模板秒杀五道算法题

评论礼仪 见这里,违者直接拉黑。

labuladong avatar Feb 05 '22 07:02 labuladong

OMG

deepbreath373 avatar Feb 07 '22 07:02 deepbreath373

小板凳坐着

mengzhibin avatar Feb 08 '22 15:02 mengzhibin

真的OMG。。。。Trie太复杂了也。。还不如拆开来说。。

wuuusicong avatar Feb 16 '22 07:02 wuuusicong

208题,R值设置为英文字母z的ascii + 1 == 123即可

bhjghjbhbfghfhfg avatar Mar 07 '22 11:03 bhjghjbhbfghfhfg

@bhjghjbhbfghfhfg 理论上 27 就够了,自己去优化就好。

labuladong avatar Mar 07 '22 15:03 labuladong

getNode那里的泛型是不是有点问题,直接对模板T的数组children赋char了

Jebearssica avatar Mar 10 '22 03:03 Jebearssica

@Jebearssica children 数组里面装的是索引,和泛型没有关系

labuladong avatar Mar 11 '22 12:03 labuladong

648题 单词替换 代码部分

// 在 Trie 树中搜索最短词根(最短前缀)
        String prefix = set.shortestPrefixOf(words[i]);
        if(prefix != null && !prefix.isEmpty()) {
            // 如果搜索到了,改写为词根
            sb.append(prefix);
        } else {
            // 否则,原样放回
            sb.append(words[i]);
        }

中间需要进行一次判空操作 , String.isEmpty() 不能对空判断

zhongweiLeex avatar Mar 12 '22 05:03 zhongweiLeex

hasKeyWithPattern 超出时间限制 需要维护一个额外记录 不然时间复杂度还是指数级别

zhongweiLeex avatar Mar 12 '22 08:03 zhongweiLeex

@zhongweiLeex 贴出你的代码

labuladong avatar Mar 12 '22 13:03 labuladong

@zhongweiLeex 贴出你的代码

  • 之前是我表达错误了,实在抱歉,是需要将前面已经匹配的剪枝。然后检查剩下的。这样就不会超出时间限制,(代码格式写的比较烂,再次抱歉!)

  • 之前的648题 搜索最短前缀部分,也是需要一个 判断 prefix != null 的操作,因为 String.isEmpty() 好像只能对 字符串判断是否是空字符串,但是不能对 空值(null)判断。

  • 在遇到通配符的时候 ,就不维护原来的,新建一个,因为如果前面的都匹配了,那前面的就必要拖着整个回溯了,直接查找后面的就行。

class WordDictionary {
    private Node root = null;
    private int size = 0;

    public WordDictionary() {
    }

    private static class Node {
        boolean end = false;
        Node[] children = new Node[26];
    }

    private Node getNode(Node node , String key){
        Node p = root;
        for (int i = 0; i < key.length(); i++) {
                if (p == null){
                    return null;
                }
                char c = key.charAt(i);
                p = p.children[c-'a'];
        }
        return p;
    }
    public boolean get(String key){
        Node p = getNode(root,key);
        if (p == null || p.end == false){
            return false;
        }
        return p.end;
    }


    public void addWord(String word) {
        root = addWord(root,word,0);
    }
    private Node addWord(Node node , String key, int i){
        if (node  == null){
            node = new Node();
        }
        if (i == key.length()){
            node.end = true;
            return node;
        }
        char c= key.charAt(i);
        node.children[c-'a'] = addWord(node.children[c-'a'],key,i+1);
        return node;
    }


    public boolean search(String word) {
        char[] pattern = word.toCharArray();
        return search(root,pattern,0);
    }
    private boolean search(Node node,char[] pattern,int i){
        if(node == null){
            return false;
        }
        if(i == pattern.length){
            return node.end;
        }
        char c = pattern[i];
        if (c == '.'){
            for (int j = 0; j < 26; j++) {
                if(node == null){
                    return false;
                }
                if (node.children[j] == null){
                    continue;
                }
                Node newNode = node.children[j];
                if (search(newNode,pattern,i+1)){
                    return true;
                }
            }
        }else{
            int k = pattern[i] - 'a';
            if(node == null){
                return false;
            }
            if (node.children[k] == null){
                return false;
            }
            node = node.children[k];
            if (search(node,pattern,i+1)){
                return true;
            }
        }
        return false;
    }
}

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary obj = new WordDictionary();
 * obj.addWord(word);
 * boolean param_2 = obj.search(word);
 */

zhongweiLeex avatar Mar 13 '22 00:03 zhongweiLeex

当Trie中只有一个元素的时候,执行remove会不会递归把root结点也删除掉?

steinstraveler avatar Mar 19 '22 02:03 steinstraveler

打卡,感谢!

bert82503 avatar May 25 '22 16:05 bert82503

ZYT2271736429 avatar Jul 06 '22 13:07 ZYT2271736429

请问set 和 map有特别具体的区别吗? 我搜了一下感觉依然云里雾里

MzxlM avatar Aug 03 '22 20:08 MzxlM

TrieSet 和TrieMap 的区别又是什么呢? 我觉得所有题目都可以用map直接写呀

MzxlM avatar Aug 04 '22 16:08 MzxlM

其实node里面不用数组,直接用hashmap就行,还省空间

FrankYJY avatar Aug 18 '22 09:08 FrankYJY

感觉648直接用string 的join比StringBuilder省事一点呢

class Solution {
    public String replaceWords(List<String> dictionary, String sentence) {
        // put the dict in a trie set and use the shortestPrefixOf method
        TrieSet dict = new TrieSet();
        for (String root : dictionary) {
            dict.add(root);
        }
        
        String[] words = sentence.split(" ");
        for (int i = 0; i < words.length; ++i) {
            String prefix = dict.shortestPrefixOf(words[i]);
            // if prefix can be found, replace
            if (!prefix.isEmpty()) {
                words[i] = prefix;
            }
            
        }        

        return String.join(" ", words);
    }
}

Hyuvo avatar Aug 20 '22 19:08 Hyuvo

211 只要把children 数组大小优化成26就不会超时啦

class WordDictionary {
    private final TrieMap<Object> map;
    
    public WordDictionary() {
        map  = new TrieMap<>();
    }
    
    public void addWord(String word) {
        // use key to store word, Object as placehoder
        map.put(word, new Object());
    }
    
    public boolean search(String word) {
        // has '.'
        return map.hasKeyWithPattern(word);
    }
}

class TrieMap<V> {
    private static final int R = 26;
    private int size = 0;
    private class TrieNode<V> {
        V val = null;
        TrieNode<V>[] children = new TrieNode[R];        
    }
    private TrieNode<V> root = null;
    
    // methods
    
    public void put(String word, V val) {
        if (!containsKey(word)) {
            size++;
        }
        root = put(root, word, val, 0);
    }
    
    private TrieNode<V> put(TrieNode<V> node, String key, V val, int i) {
        if (node == null) {
            node = new TrieNode<>();
        }
        if (i == key.length()) {
            node.val = val;
            return node;
        }
        char c = key.charAt(i);
        node.children[c - 'a'] = put(node.children[c - 'a'], key, val, i + 1);
        return node;        
    }
    
    public boolean hasKeyWithPattern(String pattern) {
        
        return hasKeyWithPattern(root, pattern, 0);
    }
    
    // recursion helper
    private boolean hasKeyWithPattern(TrieNode<V> node, String pattern, int i) {
        if (node == null) {
            // cannot continue
            return false;
        }
        if (i == pattern.length()) {
            // reaches the end
            return node.val != null;
        }
        
        char c = pattern.charAt(i);
        if (c != '.') {
            // if not .
            return hasKeyWithPattern(node.children[c - 'a'], pattern, i + 1);
        } 
            
        for (int j = 0; j < R; ++j) {
            // see every possible char, return if any has val
            if (hasKeyWithPattern(node.children[j], pattern, i + 1)) {
                // as long as one child has this patten
                return true;
            }
            // NOTE: NOT return hasKeyWithPattern(node.children[j], pattern, i + 1);        
        }
        // nothing matched
        return false;
        
    }
    
    private TrieNode<V> getNode(TrieNode<V> node, String key) {
        // search downwards from node
        TrieNode<V> p = node;
        for (int i = 0; i < key.length(); ++i) {
            if (p == null) {
                return null;
            }
            
            char c = key.charAt(i);
            p = p.children[c - 'a'];
        }
        return p;        
    }
    
    private V get(String key) {
        TrieNode<V> x = getNode(root, key);
        if(x == null || x.val == null) {
            return null;
        }
        return x.val;
    }
    
    private boolean containsKey(String key) {
        return get(key) != null;        
    }
    
}

Hyuvo avatar Aug 21 '22 00:08 Hyuvo

迷惑,,我直接套到design-add-and-search-words-data-structure里面,遇到pattern直接返回竟然比返回所有结果还慢很多,有的尝试直接TLE

FrankYJY avatar Aug 27 '22 11:08 FrankYJY

好吧,力扣运行速度浮动性太大了,直接从TLE到faster than 85了

FrankYJY avatar Aug 27 '22 11:08 FrankYJY