这两个题都提到了一种树:Trie,也叫做 prefix tree 或者 digital tree,属于所搜树的一种。通常用于字符串的分段搜索,也可以用来做输入提示,即给出一些字母,搜索后续可用的路径。搜索方式属于 DFS,每个节点可以通过带有一些属性,从而实现其他功能,比如不同的action等等。
第三题呢,乍一看跟 Trie 没关系但是,用 Trie 可以大大提高效率。
第一个题是中等,后两个都是困难题。
208. Implement Trie (Prefix Tree)
问题
A trie (pronounced as “try”) or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure, such as autocomplete and spellchecker. Implement the Trie class: Trie() Initializes the trie object. void insert(String word) Inserts the string word into the trie. boolean search(String word) Returns true if the string word is in the trie (i.e., was inserted before), and false otherwise. boolean startsWith(String prefix) Returns true if there is a previously inserted string word that has the prefix prefix, and false otherwise.
from typing importList from collections import defaultdict
classTrie:
def__init__(self): """ Initialize your data structure here. """ classNode: def__init__(self): self.children = collections.defaultdict(Node) self.end = False self.tree = Node()
definsert(self, word: str) -> None: """ Inserts a word into the trie. """ cur = self.tree for c in word: cur = cur.children[c] cur.end = True
defsearch(self, word: str) -> bool: """ Returns if the word is in the trie. """ cur = self.tree for c in word: if c notin cur.children: returnFalse else: cur = cur.children[c] return cur.end
defstartsWith(self, prefix: str) -> bool: """ Returns if there is any word in the trie that starts with the given prefix. """ cur = self.tree for c in prefix: if c notin cur.children: returnFalse else: cur = cur.children[c] returnTrue
1032. Stream of Characters
问题
Implement the StreamChecker class as follows:
StreamChecker(words): Constructor, init the data structure with the given words. query(letter): returns true if and only if for some k >= 1, the last k characters queried (in order from oldest to newest, including this letter just queried) spell one of the words in the given list.
例子
1 2 3 4 5 6 7 8 9 10 11 12 13
StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // init the dictionary. 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
for w in words: cur = root w = w[::-1] for char in w: cur = cur.children[c] # cur is now the end of the path cur.is_end = True
return root
classStreamChecker:
def__init__(self, words: List[str]): ''' Build a trie for each word in reversed order ''' # for user query record, init as empty string self.prefix = '' # for root node of trie, init as empty Trie self.trie = build_tree(words) defquery(self, letter: str) -> bool: ''' Search user input in trie with reversed order ''' self.prefix += letter cur_node = self.trie for char inreversed(self.prefix): if char notin cur_node.children: # current char not in Trie, impossible to match words break cur_node = cur_node.children[char] if cur_node.is_end: # user input match a word in Trie returnTrue # No match returnFalse
tags: LeetcodeTree
336. Palindrome Pairs
问题
Given a list of unique words, return all the pairs of the distinct indices (i, j) in the given list, so that the concatenation of the two words words[i] + words[j] is a palindrome.
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Example 1:
Input: words = ["abcd","dcba","lls","s","sssll"] Output: [[0,1],[1,0],[3,2],[2,4]] Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"] Example 2:
Input: words = ["bat","tab","cat"] Output: [[0,1],[1,0]] Explanation: The palindromes are ["battab","tabbat"] Example 3:
Input: words = ["a",""] Output: [[0,1],[1,0]]
思路
我们可以暴力解,即O(k*n^2),反复遍历检查。k 是词的长度,如果 n 远远大于 k,这个算法的效率就会非常低。
defadd_word(self, word, index): trie = self for i, c inenumerate(reversed(word)): if is_palindrome(word[0:len(word)-i]): trie.palindrome_below.append(index) trie = trie.children[c] trie.index = index
defmake_trie(words): trie = Trie1() for i, word inenumerate(words): trie.add_word(word, i) return trie
defget_palindrome(trie, word, index): res = [] while word: if trie.index >= 0: if is_palindrome(word): res.append(trie.index) ifnot word[0] in trie.children: return res
trie = trie.children[word[0]] word = word[1:]
if trie.index >= 0: res.append(trie.index) res.extend(trie.palindrome_below) return res
defsolution(words): trie = make_trie(words) res = [] for i, word inenumerate(words): selected = get_palindrome(trie, word, i) res.extend([i, c] for c in selected if i!=c) return res