@@ -84,32 +84,281 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3291.Mi
84
84
85
85
<!-- solution:start -->
86
86
87
- ### 方法一
87
+ ### 方法一:字典树 + 记忆化搜索
88
+
89
+ 我们可以使用字典树存储所有有效字符串,然后使用记忆化搜索计算答案。
90
+
91
+ 我们设计一个函数 $\textit{dfs}(i)$,表示从字符串 $\textit{target}$ 的第 $i$ 个字符开始,需要连接的最少字符串数量。那么答案就是 $\textit{dfs}(0)$。
92
+
93
+ 函数 $\textit{dfs}(i)$ 的计算方式如下:
94
+
95
+ - 如果 $i \geq n$,表示字符串 $\textit{target}$ 已经遍历完了,返回 $0$;
96
+ - 否则,我们可以从字典树中找到以 $\textit{target}[ i] $ 开头的有效字符串,然后递归计算 $\textit{dfs}(i + \text{len}(w))$,其中 $w$ 是找到的有效字符串。我们取这些值中的最小值加 $1$ 作为 $\textit{dfs}(i)$ 的返回值。
97
+
98
+ 为了避免重复计算,我们使用记忆化搜索。
99
+
100
+ 时间复杂度 $O(n^2 + L)$,空间复杂度 $O(n + L)$。其中 $n$ 是字符串 $\textit{target}$ 的长度,而 $L$ 是所有有效字符串的总长度。
88
101
89
102
<!-- tabs:start -->
90
103
91
104
#### Python3
92
105
93
106
``` python
94
-
107
+ def min (a : int , b : int ) -> int :
108
+ return a if a < b else b
109
+
110
+
111
+ class Trie :
112
+ def __init__ (self ):
113
+ self .children: List[Optional[Trie]] = [None ] * 26
114
+
115
+ def insert (self , w : str ):
116
+ node = self
117
+ for i in map (lambda c : ord (c) - 97 , w):
118
+ if node.children[i] is None :
119
+ node.children[i] = Trie()
120
+ node = node.children[i]
121
+
122
+
123
+ class Solution :
124
+ def minValidStrings (self , words : List[str ], target : str ) -> int :
125
+ @cache
126
+ def dfs (i : int ) -> int :
127
+ if i >= n:
128
+ return 0
129
+ node = trie
130
+ ans = inf
131
+ for j in range (i, n):
132
+ k = ord (target[j]) - 97
133
+ if node.children[k] is None :
134
+ break
135
+ node = node.children[k]
136
+ ans = min (ans, 1 + dfs(j + 1 ))
137
+ return ans
138
+
139
+ trie = Trie()
140
+ for w in words:
141
+ trie.insert(w)
142
+ n = len (target)
143
+ ans = dfs(0 )
144
+ return ans if ans < inf else - 1
95
145
```
96
146
97
147
#### Java
98
148
99
149
``` java
100
-
150
+ class Trie {
151
+ Trie [] children = new Trie [26 ];
152
+
153
+ void insert (String w ) {
154
+ Trie node = this ;
155
+ for (int i = 0 ; i < w. length(); ++ i) {
156
+ int j = w. charAt(i) - ' a' ;
157
+ if (node. children[j] == null ) {
158
+ node. children[j] = new Trie ();
159
+ }
160
+ node = node. children[j];
161
+ }
162
+ }
163
+ }
164
+
165
+ class Solution {
166
+ private Integer [] f;
167
+ private char [] s;
168
+ private Trie trie;
169
+ private final int inf = 1 << 30 ;
170
+
171
+ public int minValidStrings (String [] words , String target ) {
172
+ trie = new Trie ();
173
+ for (String w : words) {
174
+ trie. insert(w);
175
+ }
176
+ s = target. toCharArray();
177
+ f = new Integer [s. length];
178
+ int ans = dfs(0 );
179
+ return ans < inf ? ans : - 1 ;
180
+ }
181
+
182
+ private int dfs (int i ) {
183
+ if (i >= s. length) {
184
+ return 0 ;
185
+ }
186
+ if (f[i] != null ) {
187
+ return f[i];
188
+ }
189
+ Trie node = trie;
190
+ f[i] = inf;
191
+ for (int j = i; j < s. length; ++ j) {
192
+ int k = s[j] - ' a' ;
193
+ if (node. children[k] == null ) {
194
+ break ;
195
+ }
196
+ f[i] = Math . min(f[i], 1 + dfs(j + 1 ));
197
+ node = node. children[k];
198
+ }
199
+ return f[i];
200
+ }
201
+ }
101
202
```
102
203
103
204
#### C++
104
205
105
206
``` cpp
106
-
207
+ class Trie {
208
+ public:
209
+ Trie* children[ 26] {};
210
+
211
+ void insert(string& word) {
212
+ Trie* node = this;
213
+ for (char& c : word) {
214
+ int i = c - 'a';
215
+ if (!node->children[i]) {
216
+ node->children[i] = new Trie();
217
+ }
218
+ node = node->children[i];
219
+ }
220
+ }
221
+ };
222
+
223
+ class Solution {
224
+ public:
225
+ int minValidStrings(vector<string >& words, string target) {
226
+ int n = target.size();
227
+ Trie* trie = new Trie();
228
+ for (auto& w : words) {
229
+ trie->insert(w);
230
+ }
231
+ const int inf = 1 << 30;
232
+ int f[ n] ;
233
+ memset(f, -1, sizeof(f));
234
+ auto dfs = [ &] (auto&& dfs, int i) -> int {
235
+ if (i >= n) {
236
+ return 0;
237
+ }
238
+ if (f[ i] != -1) {
239
+ return f[ i] ;
240
+ }
241
+ f[ i] = inf;
242
+ Trie* node = trie;
243
+ for (int j = i; j < n; ++j) {
244
+ int k = target[ j] - 'a';
245
+ if (!node->children[ k] ) {
246
+ break;
247
+ }
248
+ node = node->children[ k] ;
249
+ f[ i] = min(f[ i] , 1 + dfs(dfs, j + 1));
250
+ }
251
+ return f[ i] ;
252
+ };
253
+ int ans = dfs(dfs, 0);
254
+ return ans < inf ? ans : -1;
255
+ }
256
+ };
107
257
```
108
258
109
259
#### Go
110
260
111
261
```go
262
+ type Trie struct {
263
+ children [26]*Trie
264
+ }
265
+
266
+ func (t *Trie) insert(word string) {
267
+ node := t
268
+ for _, c := range word {
269
+ idx := c - 'a'
270
+ if node.children[idx] == nil {
271
+ node.children[idx] = &Trie{}
272
+ }
273
+ node = node.children[idx]
274
+ }
275
+ }
276
+
277
+ func minValidStrings(words []string, target string) int {
278
+ n := len(target)
279
+ trie := &Trie{}
280
+ for _, w := range words {
281
+ trie.insert(w)
282
+ }
283
+ const inf int = 1 << 30
284
+ f := make([]int, n)
285
+ var dfs func(int) int
286
+ dfs = func(i int) int {
287
+ if i >= n {
288
+ return 0
289
+ }
290
+ if f[i] != 0 {
291
+ return f[i]
292
+ }
293
+ node := trie
294
+ f[i] = inf
295
+ for j := i; j < n; j++ {
296
+ k := int(target[j] - 'a')
297
+ if node.children[k] == nil {
298
+ break
299
+ }
300
+ f[i] = min(f[i], 1+dfs(j+1))
301
+ node = node.children[k]
302
+ }
303
+ return f[i]
304
+ }
305
+ if ans := dfs(0); ans < inf {
306
+ return ans
307
+ }
308
+ return -1
309
+ }
310
+ ```
112
311
312
+ #### TypeScript
313
+
314
+ ``` ts
315
+ class Trie {
316
+ children: (Trie | null )[] = Array (26 ).fill (null );
317
+
318
+ insert(word : string ): void {
319
+ let node: Trie = this ;
320
+ for (const c of word ) {
321
+ const i = c .charCodeAt (0 ) - ' a' .charCodeAt (0 );
322
+ if (! node .children [i ]) {
323
+ node .children [i ] = new Trie ();
324
+ }
325
+ node = node .children [i ];
326
+ }
327
+ }
328
+ }
329
+
330
+ function minValidStrings(words : string [], target : string ): number {
331
+ const n = target .length ;
332
+ const trie = new Trie ();
333
+ for (const w of words ) {
334
+ trie .insert (w );
335
+ }
336
+ const inf = 1 << 30 ;
337
+ const f = Array (n ).fill (0 );
338
+
339
+ const dfs = (i : number ): number => {
340
+ if (i >= n ) {
341
+ return 0 ;
342
+ }
343
+ if (f [i ]) {
344
+ return f [i ];
345
+ }
346
+ f [i ] = inf ;
347
+ let node: Trie | null = trie ;
348
+ for (let j = i ; j < n ; ++ j ) {
349
+ const k = target [j ].charCodeAt (0 ) - ' a' .charCodeAt (0 );
350
+ if (! node ?.children [k ]) {
351
+ break ;
352
+ }
353
+ node = node .children [k ];
354
+ f [i ] = Math .min (f [i ], 1 + dfs (j + 1 ));
355
+ }
356
+ return f [i ];
357
+ };
358
+
359
+ const ans = dfs (0 );
360
+ return ans < inf ? ans : - 1 ;
361
+ }
113
362
```
114
363
115
364
<!-- tabs: end -->
0 commit comments