題目地址:
https://leetcode.com/problems/replace-words/
給定一個字符串數組,再給定一個英文句子,句子裏只含英文單詞,並且以空格分隔。如果句子中的某個單詞以數組中某個字符串爲前綴,則將其替換爲這個前綴。存在多個字符串作爲其前綴,則取最短的那個。返回替換完後的英文句子。
思路是用Trie,將數組中所有字符串存進一個Trie中,然後將英文句子分割成單詞,對每個單詞尋找Trie中的最短前綴即可。代碼如下:
import java.util.List;
public class Solution {
class Trie {
class Node {
boolean isWord;
Node[] next;
Node() {
next = new Node[26];
}
}
Node root;
Trie(List<String> dict) {
root = new Node();
for (String word : dict) {
insert(word);
}
}
// 這裏的insert的時候,如果發現走到了單詞末尾就直接退出,不需要繼續添加了,
// 原因是題目只要求找最短前綴,如果兩個字符串一個是另一個的前綴,那只需要存短的那個就行了
private void insert(String word) {
Node cur = root;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (cur.next[c - 'a'] == null) {
cur.next[c - 'a'] = new Node();
}
cur = cur.next[c - 'a'];
// 遇到單詞末尾了直接退出
if (cur.isWord) {
return;
}
}
cur.isWord = true;
}
// 在Trie裏尋找word的最短前綴,並這個最短前綴返回;若不存在則返回空串
private String prefixOf(String word) {
StringBuilder sb = new StringBuilder();
Node cur = root;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
if (cur.next[c - 'a'] != null) {
// 每走一步就append路徑上的字符
cur = cur.next[c - 'a'];
sb.append(c);
} else {
// 走到null說明Trie裏不存在word的前綴,直接跳出返回空串
break;
}
// 如果第一次發現了單詞末尾,那麼就找到了最短前綴,直接返回前綴
if (cur.isWord) {
return sb.toString();
}
}
return "";
}
}
public String replaceWords(List<String> dict, String sentence) {
Trie trie = new Trie(dict);
String[] words = sentence.split(" ");
for (int i = 0; i < words.length; i++) {
String word = words[i];
// 找word的在trie中的最短前綴
String pref = trie.prefixOf(word);
// 如果pref爲空,那說明不存在前綴,跳過該單詞;否則進行替換
if (!pref.isEmpty()) {
words[i] = pref;
}
}
// 最後以空格join回來
return String.join(" ", words);
}
}
時空複雜度,爲句子的長度。