题目:
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,‘0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 ‘0000’ ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出解锁需要的最小旋转次数,如果无论如何不能解锁,返回 -1 。
解答:
class Solution:
def openLock(self, deadends: List[str], target: str) -> int:
if target=='0000':
return 0
if '0000' in deadends:
return -1
#求前驱
def num_prev(x):
return '9' if x=='0' else str(int(x)-1)
#求后继
def num_suc(x):
return '0' if x=='9' else str(int(x)+1)
#枚举经过一次旋转所能得到的所有可能的状态
def get(status):
res=[]
s=list(status)
for i in range(4):
num=s[i]
#对s[i]旋转,将其减1
s[i]=num_prev(num)
res.append(''.join(s))
#对s[i]旋转,将其加1
s[i]=num_suc(num)
res.append(''.join(s))
#恢复s[i]到原始状态
s[i]=num
return res
dead=set(deadends)
q=deque([('0000',0)])
seen={'0000'}
#BFS
while q:
status,step=q.popleft()
for next_status in get(status):
if next_status not in seen and next_status not in dead:
if next_status==target:
return step+1
q.append((next_status,step+1))
seen.add(next_status)
return -1