前缀树算法模板秒杀五道算法题 :: labuladong的算法小抄 #1032
Replies: 27 comments 5 replies
-
真的OMG。。。。Trie太复杂了也。。还不如拆开来说。。 |
Beta Was this translation helpful? Give feedback.
-
208题,R值设置为英文字母z的ascii + 1 == 123即可 |
Beta Was this translation helpful? Give feedback.
-
@bhjghjbhbfghfhfg 理论上 27 就够了,自己去优化就好。 |
Beta Was this translation helpful? Give feedback.
-
getNode那里的泛型是不是有点问题,直接对模板T的数组children赋char了 |
Beta Was this translation helpful? Give feedback.
-
@Jebearssica |
Beta Was this translation helpful? Give feedback.
-
648题 单词替换 代码部分
中间需要进行一次判空操作 , String.isEmpty() 不能对空判断 |
Beta Was this translation helpful? Give feedback.
-
hasKeyWithPattern 超出时间限制 需要维护一个额外记录 |
Beta Was this translation helpful? Give feedback.
-
@zhongweiLeex 贴出你的代码 |
Beta Was this translation helpful? Give feedback.
-
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);
*/ |
Beta Was this translation helpful? Give feedback.
-
当Trie中只有一个元素的时候,执行remove会不会递归把root结点也删除掉? |
Beta Was this translation helpful? Give feedback.
-
请问set 和 map有特别具体的区别吗? 我搜了一下感觉依然云里雾里 |
Beta Was this translation helpful? Give feedback.
-
TrieSet 和TrieMap 的区别又是什么呢? 我觉得所有题目都可以用map直接写呀 |
Beta Was this translation helpful? Give feedback.
-
其实node里面不用数组,直接用hashmap就行,还省空间 |
Beta Was this translation helpful? Give feedback.
-
感觉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);
}
} |
Beta Was this translation helpful? Give feedback.
-
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;
}
} |
Beta Was this translation helpful? Give feedback.
-
迷惑,,我直接套到design-add-and-search-words-data-structure里面,遇到pattern直接返回竟然比返回所有结果还慢很多,有的尝试直接TLE |
Beta Was this translation helpful? Give feedback.
-
好吧,力扣运行速度浮动性太大了,直接从TLE到faster than 85了 |
Beta Was this translation helpful? Give feedback.
-
有一点没太想清楚,看文章中求字符串最短前缀时,返回的是query.substring(0,i),但是看完后自己做648题时,发现我的方法中应该是i+1,然后把文章中的TrieMap和TrieSet全部拷进去运行结果也是对的,半天没有想清楚哪里不一样,下面是我的答案。 public class Solution648 {
static class TrieNode {
boolean isWord;
TrieNode[] children = new TrieNode[26];
}
TrieNode root = new TrieNode();
public String replaceWords(List<String> dictionary, String sentence) {
for (String str : dictionary) {
add(str);
}
StringBuilder sb = new StringBuilder();
for (String str : sentence.split(" ")) {
sb.append(shortestPrefixOf(str)).append(" ");
}
return sb.substring(0, sb.length() - 1);
}
private String shortestPrefixOf(String query) {
TrieNode p = root;
for (int i = 0; i < query.length(); i++) {
int idx = query.charAt(i) - 'a';
if (p.children[idx] == null) {
break;
}
if (p.children[idx].isWord) {
return query.substring(0, i + 1);//就是这里
}
p = p.children[idx];
}
return query;
}
private void add(String s) {
TrieNode p = root;
for (int i = 0; i < s.length(); i++) {
int idx = s.charAt(i) - 'a';
if (p.children[idx] == null) {
p.children[idx] = new TrieNode();
}
p = p.children[idx];
}
p.isWord = true;
}
} |
Beta Was this translation helpful? Give feedback.
-
明白了,我判断的是它的孩子节点的值,文章中判断的是它本身的值,这两种情况中的i是不一样的 |
Beta Was this translation helpful? Give feedback.
-
class TrieNode:
R = 256
def __init__(self):
self.val = None
self.children = [None for _ in range(self.R)]
class TrieMap:
R = 256
def __init__(self):
self.root = None
self.size = 0
def get_node(self, node: TrieNode, key: str) -> TrieNode|None:
"""从node开始搜索key, 若果存在返回对应节点,否则返回None"""
p = node
for i in range(len(key)):
if p is None:
return None
c = ord(key[i])
p = p.children[c]
return p
def put(self, key: str, val: any) -> None:
if not self.contains_key(key):
self.size += 1
self.root = self._put(self.root, key, val, 0)
def _put(self, node: TrieNode, key: str, val: any, i: int):
if not node:
node = TrieNode()
if i == len(key):
node.val = val
return node
c = ord(key[i])
node.children[c] = self._put(node.children[c], key, val, i+1)
return node
def remove(self, key: str):
"""
删除key
:param key:
:return:
"""
if not self.contains_key(key):
return
self.root = self._remove(self.root, key, 0)
self.size -= 1
def _remove(self, node: TrieNode, key: str, i: int):
if not node:
return None
if i == len(key):
node.val = None
else:
c = ord(key[i])
node.children[c] = self._remove(node.children[c], key, i+1)
if node.val:
return node
for c in range(self.R):
if node.children[c]:
return node
return None
def get(self, key: str):
x = self.get_node(self.root, key)
if x is None or x.val is None:
return None
return x.val
def contains_key(self, key: str) -> bool:
"""
判断key是否存在map中
:param key:
:return:
"""
return bool(self.get(key))
def has_key_with_prefix(self, prefix: str):
"""
判断是否存在前缀为prefix的key
:param prefix:
:return:
"""
return bool(self.get_node(self.root, prefix))
def shortest_prefix_of(self, query: str) -> str:
"""
从所有key中寻找query的最短前缀
:param query:
:return:
"""
p = self.root
for i in range(len(query)):
if p is None:
return ""
if p.val is not None:
return query[:i]
c = ord(query[i])
p = p.children[c]
if p is not None and p.val is not None:
# query本身就是一个key
return query
return ""
def longest_prefix_of(self, query: str) -> str:
"""
query最长前缀
:param query:
:return:
"""
p = self.root
max_len = 0
for i in range(len(query)):
if p is None:
break
if p.val is not None:
max_len = i
c = ord(query[i])
p = p.children[c]
if p is not None and p.val is not None:
return query
return query[:max_len]
def keys_with_prefix(self, prefix: str) -> List:
res = []
x = self.get_node(self.root, prefix)
if x is None:
return res
# dfs遍历x为根的树
self._traverse(x, [], res)
return res
def _traverse(self, node: TrieNode, path: List, res: List):
if not node:
return
if node.val:
res.append(''.join(path))
for c in range(self.R):
path.append(c)
self._traverse(node.children[ord(c)], path, res)
path.pop()
def has_key_with_pattern(self, pattern):
return self._has_key_with_pattern(self.root, pattern, 0)
def _has_key_with_pattern(self, node: TrieNode, pattern: str, i):
"""
匹配通配符是否存在key
:param node:
:param pattern:
:param i:
:return:
"""
if not node:
return False
if i == len(pattern):
# 到头了
return bool(node.val)
c = pattern[i]
if c != '.':
return self._has_key_with_pattern(node.children[ord(c)], pattern, i+1)
# 遇到通配符 .
for j in range(self.R):
if self._has_key_with_pattern(node.children[j], pattern, i+1):
return True
return False
def keys_with_pattern(self, pattern: str):
"""匹配所有符合pattern的key"""
res = []
self._keys_with_pattern(self.root, [], pattern, 0, res)
return res
def _keys_with_pattern(self, node: TrieNode, path: List, pattern: str, i: int, res: List):
if not node:
return
if i == len(pattern):
# pattern 匹配完成
if node.val:
res.append(''.join(path))
return
c = pattern[i]
if c == '.':
for j in range(self.R):
path.append(chr(j))
self._keys_with_pattern(node.children[j], path, pattern, i+1, res)
path.pop()
else:
path.append(c)
self._keys_with_pattern(node.children[ord(c)], path, pattern, i+1, res)
path.pop()
def __len__(self):
return self.size |
Beta Was this translation helpful? Give feedback.
-
leetcode 211题不超时的代码,按照东哥的思路写的 class WordDictionary {
private static class TrieNode{
private boolean isEnd=false;
private TrieNode[] children=new TrieNode[26];
}
TrieNode root=null;
public WordDictionary() {
root=new TrieNode();
}
public void addWord(String word) {
root=put(root,word,0);
}
private TrieNode put(TrieNode node,String word,int i){
if(node==null){
node=new TrieNode();
}
if(i==word.length()){
node.isEnd=true;
return node;
}
int c=word.charAt(i)-'a';
node.children[c]=put(node.children[c],word,i+1);
return node;
}
public boolean search(String word) {
return hasKeyWithPattern(root,word,0);
}
private boolean hasKeyWithPattern(TrieNode node,String word,int i){
if(node==null){
return false;
}
if(i==word.length()){
return node.isEnd;
}
char c=word.charAt(i);
if(c!='.'){
int b=c-'a';
return hasKeyWithPattern(node.children[b],word,i+1);
}
for(int j=0;j<26;j++){
if(hasKeyWithPattern(node.children[j],word,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);
*/ |
Beta Was this translation helpful? Give feedback.
-
Memory Limit Exceeded,该怎么办啊啊啊 |
Beta Was this translation helpful? Give feedback.
-
文章链接点这里:前缀树算法模板秒杀五道算法题
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions