BFS解决openLock

时间:2019-04-15 03:11:10

标签: python

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实现中合适的启动方式吗?

1 个答案:

答案 0 :(得分:1)

问题:

  

检查根是否被视为步骤0?
  step = -1是python实现中的适当启动方式吗?

是的,我们应该在此处使用step = -1,因为队列中的第一个元素是0000,因此不计入结果,因此我们应将step减少为-1


问题:

  

“相比之下,许多实现检查if next == target, return step +1在当前级别上混合了终止检查和扩展工作。”

这是一种提前停止的方法,因为我们已经知道它不会通过递归的终止检查,因此我们只是不输入它并对其进行修剪。它将减少一个递归深度。

但是正如您所说,在很多情况下,不建议采用此实现,因为它会混合终止检查和拉伸工作。