51
51
52
52
<!-- 这里可写通用的实现逻辑 -->
53
53
54
- BFS。
54
+ BFS 最小步数模型。本题可以用朴素 BFS,也可以用双向 BFS 优化搜索空间,从而提升效率。
55
+
56
+ 双向 BFS 是 BFS 常见的一个优化方法,主要实现思路如下:
57
+
58
+ 1 . 创建两个队列 q1, q2 分别用于“起点 -> 终点”、“终点 -> 起点”两个方向的搜索;
59
+ 2 . 创建两个哈希表 m1, m2 分别记录访问过的节点以及对应的扩展次数(步数);
60
+ 3 . 每次搜索时,优先选择元素数量较少的队列进行搜索扩展,如果在扩展过程中,搜索到另一个方向已经访问过的节点,说明找到了最短路径;
61
+ 4 . 只要其中一个队列为空,说明当前方向的搜索已经进行不下去了,说明起点到终点不连通,无需继续搜索。
62
+
63
+ ``` python
64
+ while q1 and q2:
65
+ if len (q1) <= len (q2):
66
+ # 优先选择较少元素的队列进行扩展
67
+ extend(m1, m2, q1)
68
+ else :
69
+ extend(m2, m1, q2)
70
+
71
+ def extend (m1 , m2 , q ):
72
+ # 新一轮扩展
73
+ for _ in range (len (q), 0 , - 1 ):
74
+ p = q.popleft()
75
+ step = m1[p]
76
+ for t in next (p):
77
+ if t in m1:
78
+ # 此前已经访问过
79
+ continue
80
+ if t in m2:
81
+ # 另一个方向已经搜索过,说明找到了一条最短的连通路径
82
+ return step + 1 + m2[t]
83
+ q.append(t)
84
+ m1[t] = step + 1
85
+ ```
55
86
56
87
<!-- tabs:start -->
57
88
58
89
### ** Python3**
59
90
60
91
<!-- 这里可写当前语言的特殊实现逻辑 -->
61
92
93
+ 朴素 BFS:
94
+
62
95
``` python
63
96
class Solution :
64
97
def ladderLength (self , beginWord : str , endWord : str , wordList : List[str ]) -> int :
65
98
words = set (wordList)
66
99
q = deque([beginWord])
67
100
ans = 1
68
101
while q:
69
- n = len (q)
70
- for _ in range (n ):
102
+ ans += 1
103
+ for _ in range (len (q), 0 , - 1 ):
71
104
s = q.popleft()
72
105
s = list (s)
73
106
for i in range (len (s)):
@@ -78,31 +111,65 @@ class Solution:
78
111
if t not in words:
79
112
continue
80
113
if t == endWord:
81
- return ans + 1
114
+ return ans
82
115
q.append(t)
83
116
words.remove(t)
84
117
s[i] = ch
85
- ans += 1
118
+ return 0
119
+ ```
120
+
121
+ 双向 BFS:
122
+
123
+ ``` python
124
+ class Solution :
125
+ def ladderLength (self , beginWord : str , endWord : str , wordList : List[str ]) -> int :
126
+ def extend (m1 , m2 , q ):
127
+ for _ in range (len (q), 0 , - 1 ):
128
+ s = q.popleft()
129
+ step = m1[s]
130
+ s = list (s)
131
+ for i in range (len (s)):
132
+ ch = s[i]
133
+ for j in range (26 ):
134
+ s[i] = chr (ord (' a' ) + j)
135
+ t = ' ' .join(s)
136
+ if t in m1 or t not in words:
137
+ continue
138
+ if t in m2:
139
+ return step + 1 + m2[t]
140
+ m1[t] = step + 1
141
+ q.append(t)
142
+ s[i] = ch
143
+ return - 1
144
+
145
+ words = set (wordList)
146
+ if endWord not in words:
147
+ return 0
148
+ q1, q2 = deque([beginWord]), deque([endWord])
149
+ m1, m2 = {beginWord: 0 }, {endWord: 0 }
150
+ while q1 and q2:
151
+ t = extend(m1, m2, q1) if len (q1) <= len (
152
+ q2) else extend(m2, m1, q2)
153
+ if t != - 1 :
154
+ return t + 1
86
155
return 0
87
156
```
88
157
89
158
### ** Java**
90
159
91
160
<!-- 这里可写当前语言的特殊实现逻辑 -->
92
161
162
+ 朴素 BFS:
163
+
93
164
``` java
94
165
class Solution {
95
-
96
- public int ladderLength (
97
- String beginWord ,
98
- String endWord ,
99
- List<String > wordList
100
- ) {
166
+ public int ladderLength (String beginWord , String endWord , List<String > wordList ) {
101
167
Set<String > words = new HashSet<> (wordList);
102
- Queue<String > q = new LinkedList <> ();
168
+ Queue<String > q = new ArrayDeque <> ();
103
169
q. offer(beginWord);
104
170
int ans = 1 ;
105
171
while (! q. isEmpty()) {
172
+ ++ ans;
106
173
for (int i = q. size(); i > 0 ; -- i) {
107
174
String s = q. poll();
108
175
char [] chars = s. toCharArray();
@@ -115,24 +182,79 @@ class Solution {
115
182
continue ;
116
183
}
117
184
if (endWord. equals(t)) {
118
- return ans + 1 ;
185
+ return ans;
119
186
}
120
187
q. offer(t);
121
188
words. remove(t);
122
189
}
123
190
chars[j] = ch;
124
191
}
125
192
}
126
- ++ ans;
127
193
}
128
194
return 0 ;
129
195
}
130
196
}
197
+ ```
198
+
199
+ 双向 BFS:
200
+
201
+ ``` java
202
+ class Solution {
203
+ private Set<String > words;
204
+
205
+ public int ladderLength (String beginWord , String endWord , List<String > wordList ) {
206
+ words = new HashSet<> (wordList);
207
+ if (! words. contains(endWord)) {
208
+ return 0 ;
209
+ }
210
+ Queue<String > q1 = new ArrayDeque<> ();
211
+ Queue<String > q2 = new ArrayDeque<> ();
212
+ Map<String , Integer > m1 = new HashMap<> ();
213
+ Map<String , Integer > m2 = new HashMap<> ();
214
+ q1. offer(beginWord);
215
+ q2. offer(endWord);
216
+ m1. put(beginWord, 0 );
217
+ m2. put(endWord, 0 );
218
+ while (! q1. isEmpty() && ! q2. isEmpty()) {
219
+ int t = q1. size() <= q2. size() ? extend(m1, m2, q1) : extend(m2, m1, q2);
220
+ if (t != - 1 ) {
221
+ return t + 1 ;
222
+ }
223
+ }
224
+ return 0 ;
225
+ }
131
226
227
+ private int extend (Map<String , Integer > m1 , Map<String , Integer > m2 , Queue<String > q ) {
228
+ for (int i = q. size(); i > 0 ; -- i) {
229
+ String s = q. poll();
230
+ int step = m1. get(s);
231
+ char [] chars = s. toCharArray();
232
+ for (int j = 0 ; j < chars. length; ++ j) {
233
+ char ch = chars[j];
234
+ for (char k = ' a' ; k <= ' z' ; ++ k) {
235
+ chars[j] = k;
236
+ String t = new String (chars);
237
+ if (! words. contains(t) || m1. containsKey(t)) {
238
+ continue ;
239
+ }
240
+ if (m2. containsKey(t)) {
241
+ return step + 1 + m2. get(t);
242
+ }
243
+ q. offer(t);
244
+ m1. put(t, step + 1 );
245
+ }
246
+ chars[j] = ch;
247
+ }
248
+ }
249
+ return - 1 ;
250
+ }
251
+ }
132
252
```
133
253
134
254
### ** C++**
135
255
256
+ 朴素 BFS:
257
+
136
258
``` cpp
137
259
class Solution {
138
260
public:
@@ -142,6 +264,7 @@ public:
142
264
int ans = 1;
143
265
while (!q.empty())
144
266
{
267
+ ++ans;
145
268
for (int i = q.size(); i > 0; --i)
146
269
{
147
270
string s = q.front();
@@ -153,22 +276,70 @@ public:
153
276
{
154
277
s[ j] = k;
155
278
if (!words.count(s)) continue;
156
- if (s == endWord) return ans + 1 ;
279
+ if (s == endWord) return ans;
157
280
q.push(s);
158
281
words.erase(s);
159
282
}
160
283
s[ j] = ch;
161
284
}
162
285
}
163
- ++ans;
164
286
}
165
287
return 0;
166
288
}
167
289
};
168
290
```
169
291
292
+ 双向 BFS:
293
+
294
+ ```cpp
295
+ class Solution {
296
+ public:
297
+ int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
298
+ unordered_set<string> words(wordList.begin(), wordList.end());
299
+ if (!words.count(endWord)) return 0;
300
+ queue<string> q1{{beginWord}};
301
+ queue<string> q2{{endWord}};
302
+ unordered_map<string, int> m1;
303
+ unordered_map<string, int> m2;
304
+ m1[beginWord] = 0;
305
+ m2[endWord] = 0;
306
+ while (!q1.empty() && !q2.empty())
307
+ {
308
+ int t = q1.size() <= q2.size() ? extend(m1, m2, q1, words) : extend(m2, m1, q2, words);
309
+ if (t != -1) return t + 1;
310
+ }
311
+ return 0;
312
+ }
313
+
314
+ int extend(unordered_map<string, int>& m1, unordered_map<string, int>& m2, queue<string>& q, unordered_set<string>& words) {
315
+ for (int i = q.size(); i > 0; --i)
316
+ {
317
+ string s = q.front();
318
+ int step = m1[s];
319
+ q.pop();
320
+ for (int j = 0; j < s.size(); ++j)
321
+ {
322
+ char ch = s[j];
323
+ for (char k = 'a'; k <= 'z'; ++k)
324
+ {
325
+ s[j] = k;
326
+ if (!words.count(s) || m1.count(s)) continue;
327
+ if (m2.count(s)) return step + 1 + m2[s];
328
+ m1[s] = step + 1;
329
+ q.push(s);
330
+ }
331
+ s[j] = ch;
332
+ }
333
+ }
334
+ return -1;
335
+ }
336
+ };
337
+ ```
338
+
170
339
### ** Go**
171
340
341
+ 朴素 BFS:
342
+
172
343
``` go
173
344
func ladderLength (beginWord string , endWord string , wordList []string ) int {
174
345
words := make (map [string ]bool )
@@ -178,6 +349,7 @@ func ladderLength(beginWord string, endWord string, wordList []string) int {
178
349
q := []string {beginWord}
179
350
ans := 1
180
351
for len (q) > 0 {
352
+ ans++
181
353
for i := len (q); i > 0 ; i-- {
182
354
s := q[0 ]
183
355
q = q[1 :]
@@ -191,15 +363,70 @@ func ladderLength(beginWord string, endWord string, wordList []string) int {
191
363
continue
192
364
}
193
365
if t == endWord {
194
- return ans + 1
366
+ return ans
195
367
}
196
368
q = append (q, t)
197
369
words[t] = false
198
370
}
199
371
chars[j] = ch
200
372
}
201
373
}
202
- ans++
374
+ }
375
+ return 0
376
+ }
377
+ ```
378
+
379
+ 双向 BFS:
380
+
381
+ ``` go
382
+ func ladderLength (beginWord string , endWord string , wordList []string ) int {
383
+ words := make (map [string ]bool )
384
+ for _ , word := range wordList {
385
+ words[word] = true
386
+ }
387
+ if !words[endWord] {
388
+ return 0
389
+ }
390
+
391
+ q1 , q2 := []string {beginWord}, []string {endWord}
392
+ m1 , m2 := map [string ]int {beginWord: 0 }, map [string ]int {endWord: 0 }
393
+ extend := func () int {
394
+ for i := len (q1); i > 0 ; i-- {
395
+ s := q1[0 ]
396
+ step , _ := m1[s]
397
+ q1 = q1[1 :]
398
+ chars := []byte (s)
399
+ for j := 0 ; j < len (chars); j++ {
400
+ ch := chars[j]
401
+ for k := ' a' ; k <= ' z' ; k++ {
402
+ chars[j] = byte (k)
403
+ t := string (chars)
404
+ if !words[t] {
405
+ continue
406
+ }
407
+ if _ , ok := m1[t]; ok {
408
+ continue
409
+ }
410
+ if v , ok := m2[t]; ok {
411
+ return step + 1 + v
412
+ }
413
+ q1 = append (q1, t)
414
+ m1[t] = step + 1
415
+ }
416
+ chars[j] = ch
417
+ }
418
+ }
419
+ return -1
420
+ }
421
+ for len (q1) > 0 && len (q2) > 0 {
422
+ if len (q1) > len (q2) {
423
+ m1, m2 = m2, m1
424
+ q1, q2 = q2, q1
425
+ }
426
+ t := extend ()
427
+ if t != -1 {
428
+ return t + 1
429
+ }
203
430
}
204
431
return 0
205
432
}
0 commit comments