设计搜索自动补全系统
难度:
标签:
题目描述
代码结果
运行时间: 232 ms, 内存: 18.9 MB
// Java Stream solution for LeetCode problem 642: Design Search Autocomplete System
//
// Problem Statement:
// Implement an autocomplete system using Java Streams for more concise code.
// This solution will still use a Trie data structure for efficiently storing
// and querying prefixes, but we'll leverage Streams for operations like sorting.
import java.util.*;
import java.util.stream.*;
class AutocompleteSystemStream {
private class TrieNode {
Map<Character, TrieNode> children = new HashMap<>();
Map<String, Integer> counts = new HashMap<>();
boolean isWord = false;
}
private TrieNode root = new TrieNode();
private String currentSentence = "";
public AutocompleteSystemStream(String[] sentences, int[] times) {
for (int i = 0; i < sentences.length; i++) {
add(sentences[i], times[i]);
}
}
private void add(String sentence, int time) {
TrieNode node = root;
for (char c : sentence.toCharArray()) {
node = node.children.computeIfAbsent(c, k -> new TrieNode());
node.counts.put(sentence, node.counts.getOrDefault(sentence, 0) + time);
}
node.isWord = true;
}
public List<String> input(char c) {
if (c == '#') {
add(currentSentence, 1);
currentSentence = "";
return Collections.emptyList();
}
currentSentence += c;
TrieNode node = root;
for (char cc : currentSentence.toCharArray()) {
if (!node.children.containsKey(cc)) {
return Collections.emptyList();
}
node = node.children.get(cc);
}
return node.counts.entrySet().stream()
.sorted((a, b) -> b.getValue().equals(a.getValue()) ? a.getKey().compareTo(b.getKey()) : b.getValue() - a.getValue())
.limit(3)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
}
解释
方法:
这个题解使用了一个排序列表来维护输入的句子和它们的频率。每次输入字符时,它都会筛选出以该字符开头的所有句子,并返回最频繁的前三个。当输入'#'时,它会增加当前输入句子的频率,并重新排序列表。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在`AutocompleteSystem`构造函数中,为什么选择按频率降序和字典序升序对句子进行排序?这种排序方式对性能有什么影响?
▷🦆
方法`input`中,当输入字符为'#'时,为什么要先调用`pop`再调用`insert`方法?这样处理的目的是什么?
▷🦆
在`pop`方法中,如果没有找到指定的句子,返回0有什么特殊意义?这对整个系统有何影响?
▷🦆
在`input`方法中,为什么要在每次输入非'#'字符后更新`self.sentences`和`self.idx`?这样的设计有什么优点或缺点?
▷相关问题
实现 Trie (前缀树)
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:
Trie()
初始化前缀树对象。void insert(String word)
向前缀树中插入字符串word
。boolean search(String word)
如果字符串word
在前缀树中,返回true
(即,在检索之前已经插入);否则,返回false
。boolean startsWith(String prefix)
如果之前已经插入的字符串word
的前缀之一为prefix
,返回true
;否则,返回false
。
示例:
输入 ["Trie", "insert", "search", "search", "startsWith", "insert", "search"] [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]] 输出 [null, null, true, false, true, null, true] 解释 Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 True trie.search("app"); // 返回 False trie.startsWith("app"); // 返回 True trie.insert("app"); trie.search("app"); // 返回 True
提示:
1 <= word.length, prefix.length <= 2000
word
和prefix
仅由小写英文字母组成insert
、search
和startsWith
调用次数 总计 不超过3 * 104
次