思路:BFS + 如何去重

  • root是根节点,它有几个孩子节点?
  • 不考虑去重,root有8个孩子,一共4位,增加或者减少,有两种可能,所以一共可能的变化是8种。
  • 因为题目中算的是最近距离,所以下意识想到BFS,第一次遍历到该节点,就是操作次数最小的。
  • 第一次做的时候,自己乱想,去重其实直接在队列当中弹出头结点的时候,将其加入vis就行,然后加入队列的时候再判定即可。如果在计算可能的8个节点的时候,把本身的原字符串加入**vis**,那其实只是避免了往回走,没有防止重复遍历。
    LC752.打开转盘锁 - 图1
  • 此题另外有一点值得注意:如何去记录节点所在层数:
    • 方法一:类似我这种方法,如果一层读完了,说明层数应该增加1
    • 方法二:利用一个map数据结构去记录状态, level[next_status] = level[old_status] + 1
    • 方法三:类似官方题解,每一个节点中记录两个数据:cur_valcur_depth,在插入之后,更新其状态即可。q.push(nxt_val, nxt_depth + 1)

      代码:

  1. class Solution:
  2. def numPrev(self, x: str) -> str:
  3. return "9" if x == "0" else str(int(x) - 1)
  4. def numNext(self, x: str) -> str:
  5. return "0" if x == "9" else str(int(x) + 1)
  6. def getPossibleLock(self, originalString: str) -> List[str]:
  7. allPossibleLock = list()
  8. s = list(originalString)
  9. for i in range(4):
  10. num = s[i]
  11. s[i] = self.numPrev(num)
  12. allPossibleLock.append("".join(s))
  13. s[i] = self.numNext(num)
  14. allPossibleLock.append("".join(s))
  15. s[i] = num
  16. return allPossibleLock
  17. def openLock(self, deadends: List[str], target: str) -> int:
  18. root = "0000"
  19. q = collections.deque()
  20. q.append(root)
  21. dead, visLock = set(deadends), set()
  22. countOptions = 0
  23. if root in dead:
  24. return -1
  25. while len(q):
  26. for i in range(len(q)):
  27. curNode = q.popleft()
  28. if curNode == target:
  29. return countOptions
  30. for element in self.getPossibleLock(curNode):
  31. if element not in dead and element not in visLock:
  32. q.append(element)
  33. visLock.add(element)
  34. countOptions += 1
  35. return -1