Leetcode引入了两个BFS-Template,第二个:
#Return the length of the shortest path between root and target node.
#the pseudocode
def bfs(root, target)
#declare data
queue = deque() # store all nodes which are waiting to be processed
visited = set() # store all the nodes that we've visited
#step to monitro the implemantions
step = 0; # number of steps neeeded from root to current node
# initialize
add root to queue
add root to visited;
# BFS
while (queue is not empty) {
step = step + 1;
# iterate the nodes which are already in the queue
size = len(queue);
for (int i = 0; i < size; ++i)
Node cur = the first node in queue;
return step if cur is target;
for (Node next : the neighbors of cur) #stretch .
if (next is not in used) #
add next to queue;
add next to visited;
remove the first node from queue; #
return -1; #failure
模板很清晰,因为它一次可以做一件事,
1)在terminating check
中进行Node cur = the first node in queue
;
2)在以下迭代中努力寻找邻居。
相反,当前级别的许多实现检查if next == target, return step +1
混合了终止检查和拉伸工作。
使用模板来解决openLock
问题
您的前面有4个圆形轮子的锁。每个轮子有10个插槽:
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
。轮子可以自由旋转并环绕:例如,我们可以将'9'
变成'0'
,或者将'0'
变成'9'
。每一步都包括一个轮子转动一个槽。锁最初从
'0000'
开始,这是代表4个轮子状态的字符串。系统会为您提供
deadends
死胡同的列表,这意味着如果锁显示这些密码中的任何一个,则锁的轮子将停止转动,并且您将无法打开它。给出一个
target
,该数字表示将打开锁的轮子的值,返回打开锁所需的最小总转数,如果不可能,则返回-1。示例1:
Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202" Output: 6 Explanation: A sequence of valid moves would be "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202". Note that a sequence like "0000" -> "0001" -> "0002" -> "0102" -> "0202" would be invalid, because the wheels of the lock become stuck after the display becomes the dead end "0102".
我的解决方案
class Solution5:
def openLock(self, deadends, target):
from collections import deque
#declare
queue = deque()
visited = set()
root = '0000'
#initiate
step = 0
deads = set(deadends)
queue.append(root)
visited.add(root)
if root in deads: return -1 #fast fail
while queue:
step += 1
size = len(queue)
for i in range(size):
cur = queue.popleft()
#logging.debug(f"cur: {cur}, step: {step}")
if cur == target: return step
#collect the next node.
#stretch and add next to queue
for i in range(0, 4):
for j in [-1, 1]:
nxt = cur[:i] + str((int(cur[i]) + j + 10) % 10) + cur[i+1:]
if (nxt not in deads) and (nxt not in visited):
queue.append(nxt)
visited.add(nxt)
return -1 #failure case
使用大小写进行测试:
def test_b(self):
deadends = ["8888"] #0000-> 0009 one step
target = "0009"
answer = 1
check = self.solution.openLock(deadends, target)
self.assertEqual(answer, check)
不幸的是,它报告错误
base) 10:48AM 15/04 Monday:me@host:~/Documents/Programs/Algorithms:
$ python 752.OpenTheLock.py MyCase.test_b
DEBUG cur: 0000, step: 1
DEBUG cur: 9000, step: 2
DEBUG cur: 1000, step: 2
DEBUG cur: 0900, step: 2
DEBUG cur: 0100, step: 2
DEBUG cur: 0090, step: 2
DEBUG cur: 0010, step: 2
DEBUG cur: 0009, step: 2
F
======================================================================
FAIL: test_b (__main__.MyCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "752.OpenTheLock.py", line 184, in test_b
self.assertEqual(answer, check)
AssertionError: 1 != 2
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
必须重新启动step = -1
.
----------------------------------------------------------------------
Ran 3 tests in 0.750s
OK
Templeate II的Java和C ++实现使用了预递增++step
,
那么,检查根是否视为步骤0?
step = -1
是python实现中合适的启动方式吗?
答案 0 :(得分:1)
问题:
检查根是否被视为步骤0?
step = -1是python实现中的适当启动方式吗?
是的,我们应该在此处使用step = -1
,因为队列中的第一个元素是0000
,因此不计入结果,因此我们应将step
减少为-1
问题:
“相比之下,许多实现检查
if next == target, return step +1
在当前级别上混合了终止检查和扩展工作。”
这是一种提前停止的方法,因为我们已经知道它不会通过递归的终止检查,因此我们只是不输入它并对其进行修剪。它将减少一个递归深度。
但是正如您所说,在很多情况下,不建议采用此实现,因为它会混合终止检查和拉伸工作。