Skip to content

Commit 03d9954

Browse files
committedFeb 25, 2022
feat: add solutions to lc problem: No.0752
No.0752.Open the Lock
1 parent 2112d23 commit 03d9954

File tree

2 files changed

+398
-28
lines changed

2 files changed

+398
-28
lines changed
 

‎solution/0700-0799/0752.Open the Lock/README.md

+234-24
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,15 @@
6666

6767
<!-- 这里可写通用的实现逻辑 -->
6868

69-
BFS 最小步数模型。本题可以用朴素 BFS,也可以用双向 BFS 优化搜索空间,从而提升效率。
69+
BFS 最小步数模型。
70+
71+
**方法一:朴素 BFS**
72+
73+
直接用朴素 BFS。
74+
75+
**方法二:双向 BFS**
76+
77+
本题也可以用双向 BFS 优化搜索空间,从而提升效率。
7078

7179
双向 BFS 是 BFS 常见的一个优化方法,主要实现思路如下:
7280

@@ -75,29 +83,39 @@ BFS 最小步数模型。本题可以用朴素 BFS,也可以用双向 BFS 优
7583
3. 每次搜索时,优先选择元素数量较少的队列进行搜索扩展,如果在扩展过程中,搜索到另一个方向已经访问过的节点,说明找到了最短路径;
7684
4. 只要其中一个队列为空,说明当前方向的搜索已经进行不下去了,说明起点到终点不连通,无需继续搜索。
7785

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\* 算法只能保证终点第一次出队时,即找到了一条从起点到终点的最小路径,不能保证其他点出队时也是从起点到当前点的最短路径。
101119

102120
<!-- tabs:start -->
103121

@@ -190,6 +208,54 @@ class Solution:
190208
return bfs()
191209
```
192210

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+
193259
### **Java**
194260

195261
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -319,6 +385,79 @@ class Solution {
319385
}
320386
```
321387

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+
322461
### **C++**
323462

324463
朴素 BFS:
@@ -436,6 +575,77 @@ public:
436575
};
437576
```
438577

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+
439649
### **Go**
440650
441651
朴素 BFS:

0 commit comments

Comments
 (0)