LeetCode 1032 Stream of Characters (Trie 推荐)

129 篇文章 0 订阅
60 篇文章 0 订阅

Design an algorithm that accepts a stream of characters and checks if a suffix of these characters is a string of a given array of strings words.

For example, if words = ["abc", "xyz"] and the stream added the four characters (one by one) 'a''x''y', and 'z', your algorithm should detect that the suffix "xyz" of the characters "axyz" matches "xyz" from words.

Implement the StreamChecker class:

  • StreamChecker(String[] words) Initializes the object with the strings array words.
  • boolean query(char letter) Accepts a new character from the stream and returns true if any non-empty suffix from the stream forms a word that is in words.

Example 1:

Input
["StreamChecker", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query", "query"]
[[["cd", "f", "kl"]], ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"]]
Output
[null, false, false, false, true, false, true, false, false, false, false, false, true]

Explanation
StreamChecker streamChecker = new StreamChecker(["cd", "f", "kl"]);
streamChecker.query("a"); // return False
streamChecker.query("b"); // return False
streamChecker.query("c"); // return False
streamChecker.query("d"); // return True, because 'cd' is in the wordlist
streamChecker.query("e"); // return False
streamChecker.query("f"); // return True, because 'f' is in the wordlist
streamChecker.query("g"); // return False
streamChecker.query("h"); // return False
streamChecker.query("i"); // return False
streamChecker.query("j"); // return False
streamChecker.query("k"); // return False
streamChecker.query("l"); // return True, because 'kl' is in the wordlist

Constraints:

  • 1 <= words.length <= 2000
  • 1 <= words[i].length <= 2000
  • words[i] consists of lowercase English letters.
  • letter is a lowercase English letter.
  • At most 4 * 104 calls will be made to query.

题目连接:https://leetcode.com/problems/stream-of-characters/

题目大意:给一个字典,和一段字符流,判断字符流中是否存在某个子串在字典中

题目分析:最暴力的做法是用字典正序建Trie,将当前匹配的树节点存下来,对于下一个字符,如果依旧匹配则继续往后,否则删除

1347ms,时间击败5%

class StreamChecker {

    class TrieNode {
        TrieNode[] nxt;
        boolean isWord;
        TrieNode() {
            this.nxt = new TrieNode[26];
            this.isWord = false; 
        }
    }
    
    private void insertTrie(TrieNode root, char[] s) {
        TrieNode p = root;
        for (int i = 0; i < s.length; i++) {
            int idx = s[i] - 'a';
            if (p.nxt[idx] == null) {
                p.nxt[idx] = new TrieNode();
            }
            p = p.nxt[idx];
        }
        p.isWord = true;
    }
    
    private List<TrieNode> trieNodeList;
    private TrieNode root;
    
    public StreamChecker(String[] words) {
        this.trieNodeList = new ArrayList<>();
        this.root = new TrieNode();
        for (int i = 0; i < words.length; i++) {
            this.insertTrie(this.root, words[i].toCharArray());
        }
    }
    
    public boolean query(char letter) {
        int idx = letter - 'a';
        
        List<TrieNode> tmp = new ArrayList();
        boolean find = false;
        for (TrieNode tn : this.trieNodeList) {
            if (tn.nxt[idx] != null) {
                tn = tn.nxt[idx];
                tmp.add(tn);
                if (tn.isWord) {
                    find = true;
                }
            }
        }
        TrieNode p = root;
        if (p.nxt[idx] != null) {
            p = p.nxt[idx];
            tmp.add(p);
            if (p.isWord) {
                find = true;
            }
        }
        this.trieNodeList = tmp;
        
        return find;
    }
}

/**
 * Your StreamChecker object will be instantiated and called as such:
 * StreamChecker obj = new StreamChecker(words);
 * boolean param_1 = obj.query(letter);
 */

其实上面的做法没有充分利用到Trie的高效查找,Trie的查找效率是log的,因此可以针对每个后缀直接在trie上查,因为要查后缀,故建Trie的时候可以将单词逆序插入

128ms,时间击败30%,这题的数据不知是不是后期增强了,原来跑77ms的代码再跑也是150+ms

class StreamChecker {

    class TrieNode {
        TrieNode[] nxt;
        boolean isWord;
        TrieNode() {
            this.nxt = new TrieNode[26];
            this.isWord = false;
        }
    }
    
    private void insertTrie(TrieNode root, char[] s) {
        TrieNode p = root;
        for (int i = s.length - 1; i >= 0; i--) {
            int idx = s[i] - 'a';
            if (p.nxt[idx] == null) {
                p.nxt[idx] = new TrieNode();
            }
            p = p.nxt[idx];
        }
        p.isWord = true;
    }
    
    private StringBuilder sb;
    private TrieNode root;
    
    public StreamChecker(String[] words) {
        this.sb = new StringBuilder();
        this.root = new TrieNode();
        for (int i = 0; i < words.length; i++) {
            this.insertTrie(this.root, words[i].toCharArray());
        }
    }
    
    public boolean query(char letter) {
        this.sb.append(letter);
        TrieNode p = this.root;
        for (int i = sb.length() - 1; i >= 0; i--) {
            int idx = sb.charAt(i) - 'a';
            if (p.nxt[idx] != null) {
                p = p.nxt[idx];
                if (p.isWord) {
                    return true;
                }
            } else {
                return false;
            }
        }
  
        return p.isWord;
    }
}

/**
 * Your StreamChecker object will be instantiated and called as such:
 * StreamChecker obj = new StreamChecker(words);
 * boolean param_1 = obj.query(letter);
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值