66
66
67
67
<!-- 这里可写通用的实现逻辑 -->
68
68
69
- BFS 最小步数模型。本题可以用朴素 BFS,也可以用双向 BFS 优化搜索空间,从而提升效率。
69
+ BFS 最小步数模型。
70
+
71
+ ** 方法一:朴素 BFS**
72
+
73
+ 直接用朴素 BFS。
74
+
75
+ ** 方法二:双向 BFS**
76
+
77
+ 本题也可以用双向 BFS 优化搜索空间,从而提升效率。
70
78
71
79
双向 BFS 是 BFS 常见的一个优化方法,主要实现思路如下:
72
80
@@ -75,29 +83,39 @@ BFS 最小步数模型。本题可以用朴素 BFS,也可以用双向 BFS 优
75
83
3 . 每次搜索时,优先选择元素数量较少的队列进行搜索扩展,如果在扩展过程中,搜索到另一个方向已经访问过的节点,说明找到了最短路径;
76
84
4 . 只要其中一个队列为空,说明当前方向的搜索已经进行不下去了,说明起点到终点不连通,无需继续搜索。
77
85
78
- ``` python
79
- while q1 and q2:
80
- if len (q1) <= len (q2):
81
- # 优先选择较少元素的队列进行扩展
82
- extend(m1, m2, q1)
83
- else :
84
- extend(m2, m1, q2)
85
-
86
- def extend (m1 , m2 , q ):
87
- # 新一轮扩展
88
- for _ in range (len (q), 0 , - 1 ):
89
- p = q.popleft()
90
- step = m1[p]
91
- for t in next (p):
92
- if t in m1:
93
- # 此前已经访问过
94
- continue
95
- if t in m2:
96
- # 另一个方向已经搜索过,说明找到了一条最短的连通路径
97
- return step + 1 + m2[t]
98
- q.append(t)
99
- m1[t] = step + 1
100
- ```
86
+ ``` python
87
+ while q1 and q2:
88
+ if len (q1) <= len (q2):
89
+ # 优先选择较少元素的队列进行扩展
90
+ extend(m1, m2, q1)
91
+ else :
92
+ extend(m2, m1, q2)
93
+
94
+ def extend (m1 , m2 , q ):
95
+ # 新一轮扩展
96
+ for _ in range (len (q), 0 , - 1 ):
97
+ p = q.popleft()
98
+ step = m1[p]
99
+ for t in next (p):
100
+ if t in m1:
101
+ # 此前已经访问过
102
+ continue
103
+ if t in m2:
104
+ # 另一个方向已经搜索过,说明找到了一条最短的连通路径
105
+ return step + 1 + m2[t]
106
+ q.append(t)
107
+ m1[t] = step + 1
108
+ ```
109
+
110
+ ** 方法三:A\* 算法**
111
+
112
+ A\* 算法主要思想如下:
113
+
114
+ 1 . 将 BFS 队列转换为优先队列(小根堆);
115
+ 1 . 队列中的每个元素为 ` (dist[state] + f(state), state) ` ,` dist[state] ` 表示从起点到当前 state 的距离,` f(state) ` 表示从当前 state 到终点的估计距离,这两个距离之和作为堆排序的依据;
116
+ 1 . 当终点第一次出队时,说明找到了从起点到终点的最短路径,直接返回对应的 step;
117
+ 1 . ` f(state) ` 是估价函数,并且估价函数要满足 ` f(state) <= g(state) ` ,其中 ` g(state) ` 表示 state 到终点的真实距离;
118
+ 1 . A\* 算法只能保证终点第一次出队时,即找到了一条从起点到终点的最小路径,不能保证其他点出队时也是从起点到当前点的最短路径。
101
119
102
120
<!-- tabs:start -->
103
121
@@ -190,6 +208,54 @@ class Solution:
190
208
return bfs()
191
209
```
192
210
211
+ A\* 算法:
212
+
213
+ ``` python
214
+ class Solution :
215
+ def openLock (self , deadends : List[str ], target : str ) -> int :
216
+ def next (s ):
217
+ res = []
218
+ s = list (s)
219
+ for i in range (4 ):
220
+ c = s[i]
221
+ s[i] = ' 9' if c == ' 0' else str (int (c) - 1 )
222
+ res.append(' ' .join(s))
223
+ s[i] = ' 0' if c == ' 9' else str (int (c) + 1 )
224
+ res.append(' ' .join(s))
225
+ s[i] = c
226
+ return res
227
+
228
+ def f (s ):
229
+ ans = 0
230
+ for i in range (4 ):
231
+ a = ord (s[i]) - ord (' 0' )
232
+ b = ord (target[i]) - ord (' 0' )
233
+ if a > b:
234
+ a, b = b, a
235
+ ans += min (b - a, a + 10 - b)
236
+ return ans
237
+
238
+ if target == ' 0000' :
239
+ return 0
240
+ s = set (deadends)
241
+ if ' 0000' in s:
242
+ return - 1
243
+ start = ' 0000'
244
+ q = [(f(start), start)]
245
+ dist = {start: 0 }
246
+ while q:
247
+ _, state = heapq.heappop(q)
248
+ if state == target:
249
+ return dist[state]
250
+ for t in next (state):
251
+ if t in s:
252
+ continue
253
+ if t not in dist or dist[t] > dist[state] + 1 :
254
+ dist[t] = dist[state] + 1
255
+ heapq.heappush(q, (dist[t] + f(t), t))
256
+ return - 1
257
+ ```
258
+
193
259
### ** Java**
194
260
195
261
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -319,6 +385,79 @@ class Solution {
319
385
}
320
386
```
321
387
388
+ A\* 算法:
389
+
390
+ ``` java
391
+ class Solution {
392
+ private String target;
393
+
394
+ public int openLock (String [] deadends , String target ) {
395
+ if (" 0000" . equals(target)) {
396
+ return 0 ;
397
+ }
398
+ String start = " 0000" ;
399
+ this . target = target;
400
+ Set<String > s = new HashSet<> ();
401
+ for (String d : deadends) {
402
+ s. add(d);
403
+ }
404
+ if (s. contains(start)) {
405
+ return - 1 ;
406
+ }
407
+ PriorityQueue<Pair<Integer , String > > q = new PriorityQueue<> (Comparator . comparingInt(Pair :: getKey));
408
+ q. offer(new Pair<> (f(start), start));
409
+ Map<String , Integer > dist = new HashMap<> ();
410
+ dist. put(start, 0 );
411
+ while (! q. isEmpty()) {
412
+ String state = q. poll(). getValue();
413
+ int step = dist. get(state);
414
+ if (target. equals(state)) {
415
+ return step;
416
+ }
417
+ for (String t : next(state)) {
418
+ if (s. contains(t)) {
419
+ continue ;
420
+ }
421
+ if (! dist. containsKey(t) || dist. get(t) > step + 1 ) {
422
+ dist. put(t, step + 1 );
423
+ q. offer(new Pair<> (step + 1 + f(t), t));
424
+ }
425
+ }
426
+ }
427
+ return - 1 ;
428
+ }
429
+
430
+ private int f (String s ) {
431
+ int ans = 0 ;
432
+ for (int i = 0 ; i < 4 ; ++ i) {
433
+ int a = s. charAt(i) - ' 0' ;
434
+ int b = target. charAt(i) - ' 0' ;
435
+ if (a > b) {
436
+ int t = a;
437
+ a = b;
438
+ b = a;
439
+ }
440
+ ans += Math . min(b - a, a + 10 - b);
441
+ }
442
+ return ans;
443
+ }
444
+
445
+ private List<String > next (String t ) {
446
+ List res = new ArrayList<> ();
447
+ char [] chars = t. toCharArray();
448
+ for (int i = 0 ; i < 4 ; ++ i) {
449
+ char c = chars[i];
450
+ chars[i] = c == ' 0' ? ' 9' : (char ) (c - 1 );
451
+ res. add(String . valueOf(chars));
452
+ chars[i] = c == ' 9' ? ' 0' : (char ) (c + 1 );
453
+ res. add(String . valueOf(chars));
454
+ chars[i] = c;
455
+ }
456
+ return res;
457
+ }
458
+ }
459
+ ```
460
+
322
461
### ** C++**
323
462
324
463
朴素 BFS:
@@ -436,6 +575,77 @@ public:
436
575
};
437
576
```
438
577
578
+ A\* 算法:
579
+
580
+ ``` cpp
581
+ class Solution {
582
+ public:
583
+ string target;
584
+
585
+ int openLock(vector<string>& deadends, string target) {
586
+ if (target == "0000") return 0;
587
+ unordered_set<string> s(deadends.begin(), deadends.end());
588
+ if (s.count("0000")) return -1;
589
+ string start = "0000";
590
+ this->target = target;
591
+ typedef pair<int , string> PIS;
592
+ priority_queue<PIS, vector<PIS>, greater<PIS>> q;
593
+ unordered_map<string, int> dist;
594
+ dist[start] = 0;
595
+ q.push({f(start), start});
596
+ while (!q.empty())
597
+ {
598
+ PIS t = q.top();
599
+ q.pop();
600
+ string state = t.second;
601
+ int step = dist[state];
602
+ if (state == target) return step;
603
+ for (string& t : next(state))
604
+ {
605
+ if (s.count(t)) continue;
606
+ if (!dist.count(t) || dist[t] > step + 1)
607
+ {
608
+ dist[t] = step + 1;
609
+ q.push({step + 1 + f(t), t});
610
+ }
611
+ }
612
+ }
613
+ return -1 ;
614
+ }
615
+
616
+ int f (string s) {
617
+ int ans = 0;
618
+ for (int i = 0; i < 4; ++i)
619
+ {
620
+ int a = s[ i] - '0';
621
+ int b = target[ i] - '0';
622
+ if (a < b)
623
+ {
624
+ int t = a;
625
+ a = b;
626
+ b = t;
627
+ }
628
+ ans += min(b - a, a + 10 - b);
629
+ }
630
+ return ans;
631
+ }
632
+
633
+ vector<string> next(string& t) {
634
+ vector<string> res;
635
+ for (int i = 0; i < 4; ++i)
636
+ {
637
+ char c = t[i];
638
+ t[i] = c == '0' ? '9' : (char) (c - 1);
639
+ res.push_back(t);
640
+ t[i] = c == '9' ? '0' : (char) (c + 1);
641
+ res.push_back(t);
642
+ t[i] = c;
643
+ }
644
+ return res;
645
+ }
646
+ };
647
+ ```
648
+
439
649
### **Go**
440
650
441
651
朴素 BFS:
0 commit comments