752. 開啟轉盤鎖
你有乙個帶有四個圓形撥輪的轉盤鎖。每個撥輪都有10個數字: 『0』, 『1』, 『2』, 『3』, 『4』, 『5』, 『6』, 『7』, 『8』, 『9』 。每個撥輪可以自由旋**例如把 『9』 變為 『0』,『0』 變為 『9』 。每次旋轉都只能旋轉乙個撥輪的一位數字。
鎖的初始數字為 『0000』 ,乙個代表四個撥輪的數字的字串。
列表 deadends 包含了一組死亡數字,一旦撥輪的數字和列表裡的任何乙個元素相同,這個鎖將會被永久鎖定,無法再被旋轉。
字串 target 代表可以解鎖的數字,你需要給出最小的旋轉次數,如果無論如何不能解鎖,返回 -1。
示例 1:
輸入:deadends = [「0201」,「0101」,「0102」,「1212」,「2002」], target = 「0202」
輸出:6
解釋:可能的移動序列為 「0000」 -> 「1000」 -> 「1100」 -> 「1200」 -> 「1201」 -> 「1202」 -> 「0202」。
注意 「0000」 -> 「0001」 -> 「0002」 -> 「0102」 -> 「0202」 這樣的序列是不能解鎖的,
因為當撥動到 「0102」 時這個鎖就會被鎖定。
示例 2:
輸入: deadends = [「8888」], target = 「0009」
輸出:1
解釋:把最後一位反向旋轉一次即可 「0000」 -> 「0009」。
示例 3:
輸入: deadends = [「8887」,「8889」,「8878」,「8898」,「8788」,「8988」,「7888」,「9888」], target = 「8888」
輸出:-1
解釋:無法旋轉到目標數字且不被鎖定。
示例 4:
輸入: deadends = [「0000」], target = 「8888」
輸出:-1
鎖盤有四個鍵,每乙個鍵每一有兩種變換的可能,所以個原始輸入進去,會產生8個後續的變化可能。
但是我們有乙個死區dead,和乙個走過的數字visited。這兩類內的數字就不能在實際產生並且加入到queue佇列中。
下面是一種單向的bfs方法求解的過程:
class
solution
:def
openlock
(self, deadends: list[
str]
, target:
str)
->
int:
if'0000'
in deadends:
return-1
queue = collections.deque(
)'0000'
)#加入佇列
visited =
set(
)#建立乙個集合,儲存走過的路,防止往回走
step =
1while queue:
for i in
range
(len
(queue)):
#每次需要迴圈多少次
cur = queue.popleft(
)for j in
range(4
):#由於有四個滑動鍵,每乙個有兩種變換(加減)
for k in[-
1,1]
: tempcur = cur[
:j]+
str(
(int
(cur[j]
)+k+10)
%10)+ cur[j+1:
]if tempcur not
in deadends:
if tempcur == target:
return step
if tempcur not
in visited:
#沒有走過,加入到佇列
visited.add(tempcur)
#加入走過的集合
step +=
1return
-1
這裡我們還考慮是否能使用雙向的bfs,因為雙向的bfs的使用條件是,我們必須直到起始點和終點。有了這兩個點的資訊,我們才能夠雙向的往中間靠,減少複雜度和計算時間。
雙向bfs和單向bfs在程式上的區別就是,雙向的bfs,我們設定的資料型別是list, list也可以左右pop。
其次,最重要的是:我們在每次遍歷bfs的時候,我們都是遍歷的queue, 每次結束遍歷的的時候,我們queue2 - > queue,把目標列表賦值給起始列表,其實列表的下一批結果賦值給目標列表。
這樣做的目的就是,單次交叉bfs,減少中間過程產生的結果。並且每次都只迴圈乙個列表,減少了程式的複雜度。
class
solution
:def
openlock
(self, deadends: list[
str]
, target:
str)
->
int:
if'0000'
in deadends:
return-1
queue =
'0000'
)#加入佇列
deadends =
set(deadends)
queue2 =
[target]
visited =
set(
)#建立乙個集合,儲存走過的路,防止往回走
visited.add(
'0000'
) step =
1while queue and queue2:
qlen =
len(queue)
tempset =
#設定本次queue的下一批可能節點,最後賦值給queue2,交叉bfs
for i in
range
(qlen)
:#每次需要迴圈多少次
cur = queue.pop(0)
for j in
range(4
):for k in[-
1,1]
: tempcur = cur[
:j]+
str(
(int
(cur[j]
)+k+10)
%10)+ cur[j+1:
]if tempcur not
in deadends:
if tempcur in queue2:
return step
if tempcur not
in visited:
#沒有走過,加入到佇列
visited.add(tempcur)
#加入走過的集合
step +=
1 queue = queue2#目標值queue2列表賦值給queue
queue2 = tempset#本次queue的下一批節點賦值給queue2
return
-1
開啟轉盤鎖(LeetCode 752)
你有乙個帶有四個圓形撥輪的轉盤鎖。每個撥輪都有10個數字 0 1 2 3 4 5 6 7 8 9 每個撥輪可以自由旋 例如把 9 變為 0 0 變為 9 每次旋轉都只能旋轉乙個撥輪的一位數字。鎖的初始數字為 0000 乙個代表四個撥輪的數字的字串。列表 deadends 包含了一組死亡數字,一旦撥輪...
leetcode 752 開啟轉盤鎖
目錄你的鼓勵也是我創作的動力 你有乙個帶有四個圓形撥輪的轉盤鎖。每個撥輪都有10個數字 0 1 2 3 4 5 6 7 8 9 每個撥輪可以自由旋 例如把 9 變為 0 0 變為 9 每次旋轉都只能旋轉乙個撥輪的一位數字。鎖的初始數字為 0000 乙個代表四個撥輪的數字的字串。列表 deadends...
leetcode752 開啟轉盤鎖
我們可以將 0000 到 9999 這 10000 狀態看成圖上的 10000 個節點,兩個節點之間存在一條邊,當且僅當這兩個節點對應的狀態只有 1 位不同,且不同的那位相差 1 包括 0 和 9 也相差 1 的情況 並且這兩個節點均不在陣列 deadends 中。那麼最終的答案即為 0000 到 ...