Skip to content

Commit 0f28571

Browse files
committedDec 28, 2021
feat: add solutions to lc problem: No.0472
No.0472.Concatenated Words
1 parent 092fa81 commit 0f28571

File tree

6 files changed

+630
-0
lines changed

6 files changed

+630
-0
lines changed
 

‎solution/0400-0499/0472.Concatenated Words/README.md

+224
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,246 @@
4343

4444
<!-- 这里可写通用的实现逻辑 -->
4545

46+
前缀树(字典树) + DFS。
47+
48+
判断一个单词是不是连接词,需要判断这个单词是否完全由至少两个给定数组中的更短的非空单词(可以重复)组成。判断更短的单词是否在给定数组中,可以使用字典树实现。
49+
50+
首先将 words 按照字符串的长度递增的顺序排序,排序后可以确保当遍历到任意单词时,比该单词短的单词一定都已经遍历过,因此可以根据已经遍历过的全部单词判断当前单词是不是连接词。
51+
52+
在将 words 排序之后,遍历 words,跳过空字符串,对于每个非空单词,判断该单词是不是连接词,如果是连接词则将该单词加入结果数组,如果不是连接词则将该单词加入字典树。
53+
54+
判断一个单词是不是连接词的做法是在字典树中深度优先搜索。从该单词的第一个字符(即下标 0 处的字符)开始,在字典树中依次搜索每个字符对应的结点,可能有以下几种情况:
55+
56+
- 如果一个字符对应的结点是单词的结尾,则找到了一个更短的单词,从该字符的后一个字符开始搜索下一个更短的单词;
57+
- 如果一个字符对应的结点在字典树中不存在,则当前的搜索结果失败,回到上一个单词的结尾继续搜索。
58+
59+
如果找到一个更短的单词且这个更短的单词的最后一个字符是当前单词的最后一个字符,则当前单词是连接词。由于数组 words 中没有重复的单词,因此在判断一个单词是不是连接词时,该单词一定没有加入字典树,由此可以确保判断连接词的条件成立。
60+
61+
说明:由于一个连接词由多个更短的非空单词组成,如果存在一个较长的连接词的组成部分之一是一个较短的连接词,则一定可以将这个较短的连接词换成多个更短的非空单词,因此**不需要将连接词加入字典树**
62+
4663
<!-- tabs:start -->
4764

4865
### **Python3**
4966

5067
<!-- 这里可写当前语言的特殊实现逻辑 -->
5168

5269
```python
70+
class Trie:
71+
def __init__(self):
72+
self.children = [None] * 26
73+
self.is_end = False
74+
75+
76+
class Solution:
77+
def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]:
78+
trie = Trie()
79+
words.sort(key=lambda x: len(x))
80+
ans = []
81+
82+
def insert(word):
83+
node = trie
84+
for c in word:
85+
idx = ord(c) - ord('a')
86+
if node.children[idx] is None:
87+
node.children[idx] = Trie()
88+
node = node.children[idx]
89+
node.is_end = True
5390

91+
def dfs(word):
92+
node = trie
93+
if not word:
94+
return True
95+
for i, c in enumerate(word):
96+
idx = ord(c) - ord('a')
97+
node = node.children[idx]
98+
if node is None:
99+
return False
100+
if node.is_end:
101+
if dfs(word[i + 1:]):
102+
return True
103+
return False
104+
105+
for word in words:
106+
if not word:
107+
continue
108+
if dfs(word):
109+
ans.append(word)
110+
else:
111+
insert(word)
112+
return ans
54113
```
55114

56115
### **Java**
57116

58117
<!-- 这里可写当前语言的特殊实现逻辑 -->
59118

60119
```java
120+
class Solution {
121+
private Trie trie;
122+
123+
public List<String> findAllConcatenatedWordsInADict(String[] words) {
124+
Arrays.sort(words, Comparator.comparingInt(String::length));
125+
List<String> ans = new ArrayList<>();
126+
trie = new Trie();
127+
for (String word : words) {
128+
if ("".equals(word)) {
129+
continue;
130+
}
131+
if (dfs(word, 0)) {
132+
ans.add(word);
133+
} else {
134+
insert(word);
135+
}
136+
}
137+
return ans;
138+
}
139+
140+
private boolean dfs(String word, int u) {
141+
if (word.length() == u) {
142+
return true;
143+
}
144+
Trie node = trie;
145+
for (int i = u; i < word.length(); ++i) {
146+
int idx = word.charAt(i) - 'a';
147+
node = node.children[idx];
148+
if (node == null) {
149+
return false;
150+
}
151+
if (node.isEnd) {
152+
if (dfs(word, i + 1)) {
153+
return true;
154+
}
155+
}
156+
}
157+
return false;
158+
}
159+
160+
private void insert(String word) {
161+
Trie node = trie;
162+
for (char c : word.toCharArray()) {
163+
int idx = c - 'a';
164+
if (node.children[idx] == null) {
165+
node.children[idx] = new Trie();
166+
}
167+
node = node.children[idx];
168+
}
169+
node.isEnd = true;
170+
}
171+
}
172+
173+
class Trie {
174+
Trie[] children = new Trie[26];
175+
boolean isEnd;
176+
}
177+
```
178+
179+
### **C++**
180+
181+
```cpp
182+
class Trie {
183+
public:
184+
vector<Trie*> children;
185+
bool isEnd;
186+
Trie(): children(26), isEnd(false) {}
187+
};
188+
189+
class Solution {
190+
public:
191+
Trie* trie;
192+
193+
vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
194+
sort(words.begin(), words.end(), [&](const string & a, const string & b){
195+
return a.size() < b.size();
196+
});
197+
vector<string> ans;
198+
trie = new Trie();
199+
for (auto& word : words)
200+
{
201+
if (word.size() == 0) continue;
202+
if (dfs(word, 0)) ans.push_back(word);
203+
else insert(word);
204+
}
205+
return ans;
206+
}
207+
208+
bool dfs(string word, int u) {
209+
Trie* node = trie;
210+
if (u == word.size()) return true;
211+
for (int i = u; i < word.size(); ++i)
212+
{
213+
int idx = word[i] - 'a';
214+
node = node->children[idx];
215+
if (!node) return false;
216+
if (node->isEnd && dfs(word, i + 1)) return true;
217+
}
218+
return false;
219+
}
220+
221+
void insert(string word) {
222+
Trie* node = trie;
223+
for (char c : word)
224+
{
225+
int idx = c - 'a';
226+
if (!node->children[idx]) node->children[idx] = new Trie();
227+
node = node->children[idx];
228+
}
229+
node->isEnd = true;
230+
}
231+
};
232+
```
233+
234+
### **Go**
235+
236+
```go
237+
type trie struct {
238+
children [26]*trie
239+
isEnd bool
240+
}
241+
242+
func (root *trie) insert(word string) {
243+
node := root
244+
for _, c := range word {
245+
c -= 'a'
246+
if node.children[c] == nil {
247+
node.children[c] = &trie{}
248+
}
249+
node = node.children[c]
250+
}
251+
node.isEnd = true
252+
}
253+
254+
func (root *trie) dfs(word string) bool {
255+
if word == "" {
256+
return true
257+
}
258+
node := root
259+
for i, c := range word {
260+
node = node.children[c-'a']
261+
if node == nil {
262+
return false
263+
}
264+
if node.isEnd && root.dfs(word[i+1:]) {
265+
return true
266+
}
267+
}
268+
return false
269+
}
61270
271+
func findAllConcatenatedWordsInADict(words []string) (ans []string) {
272+
sort.Slice(words, func(i, j int) bool { return len(words[i]) < len(words[j]) })
273+
root := &trie{}
274+
for _, word := range words {
275+
if word == "" {
276+
continue
277+
}
278+
if root.dfs(word) {
279+
ans = append(ans, word)
280+
} else {
281+
root.insert(word)
282+
}
283+
}
284+
return
285+
}
62286
```
63287

64288
### **...**

0 commit comments

Comments
 (0)