You see, madness, as you know, is like gravity. All it takes is a little push!
瘋狂就像地心引力,需要做的只是輕輕一推。 你有一個帶有四個圓形撥輪的轉(zhuǎn)盤鎖。每個撥輪都有10個數(shù)字:'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每個撥輪可以自由旋轉(zhuǎn):例如把 '9' 變?yōu)?0','0' 變?yōu)?'9' 。每次旋轉(zhuǎn)都只能旋轉(zhuǎn)一個撥輪的一位數(shù)字。 鎖的初始數(shù)字為 '0000' ,一個代表四個撥輪的數(shù)字的字符串。 列表 deadends 包含了一組死亡數(shù)字,一旦撥輪的數(shù)字和列表里的任何一個元素相同,這個鎖將會被永久鎖定,無法再被旋轉(zhuǎn)。 字符串target 代表可以解鎖的數(shù)字,你需要給出最小的旋轉(zhuǎn)次數(shù),如果無論如何不能解鎖,返回 -1。 示例 1: 輸入: deadends = ["0201","0101","0102","1212","2002"], target = "0202" 輸出:6 解釋: 可能的移動序列為 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。 注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 這樣的序列是不能解鎖的, 因為當(dāng)撥動到 "0102" 時這個鎖就會被鎖定。
示例 2: 輸入: deadends = ["8888"], target = "0009" 輸出:1 解釋: 把最后一位反向旋轉(zhuǎn)一次即可 "0000" -> "0009"。
示例 3:
輸入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888" 輸出:-1 解釋: 無法旋轉(zhuǎn)到目標(biāo)數(shù)字且不被鎖定。
示例 4: 輸入: deadends = ["0000"], target = "8888" 輸出:-1
提示: 死亡列表 deadends 的長度范圍為 [1, 500]。 目標(biāo)數(shù)字 target 不會在 deadends 之中。 每個 deadends 和 target 中的字符串的數(shù)字會在 10,000 個可能的情況 '0000' 到 '9999' 中產(chǎn)生。
以字符串"0000"為起始點,把它的每一位都分別加1和減1,總共會有8個結(jié)果,如下圖所示,細(xì)心的同學(xué)可能發(fā)現(xiàn)了,這不就是一棵8叉樹嗎,二叉樹是有2個子節(jié)點,那么8叉樹肯定就是8個子節(jié)點了。
這是一棵以"0000"為根節(jié)點的8叉樹,我們一層一層的遍歷他的每個節(jié)點,如果找到就返回他所在的層數(shù)即可,如果當(dāng)前層遍歷完了還沒找到就遍歷下一層,直到找到為止,如果都遍歷完了還沒找到就返回-1。所以我們很容易想到BFS 注意這棵樹并不是無線的延伸下去的,因為樹中所有的節(jié)點都不能重復(fù),否則會出現(xiàn)死循環(huán)。比如"0000"的子節(jié)點包含"0001",但"0001"的子節(jié)點不能再包含"0000"了。并且子節(jié)點中還不能包含死亡數(shù)字。
搞懂了上面的分析過程,代碼就容易多了 之前講過二叉樹的BFS遍歷,具體可以看下《373,數(shù)據(jù)結(jié)構(gòu)-6,樹》,他就是一層一層的往下遍歷的,如下圖所示 二叉樹的BFS代碼我們可以這樣寫 1public void levelOrder(TreeNode tree) { 2 Queue<TreeNode> queue = new LinkedList<>(); 3 queue.add(tree); 4 int level = 0;//統(tǒng)計有多少層 5 while (!queue.isEmpty()) { 6 //每一層的節(jié)點數(shù) 7 int size = queue.size(); 8 for (int i = 0; i < size; i++) { 9 TreeNode node = queue.poll(); 10 //打印節(jié)點 11 System.out.println(node.val); 12 if (node.left != null) 13 queue.add(node.left); 14 if (node.right != null) 15 queue.add(node.right); 16 } 17 level++; 18 //打印第幾層 19 System.out.println(level); 20 } 21}
二叉樹的BFS打印我們搞懂了之后,那么不管是8叉樹還是100叉樹,打印其實都是一樣的,我們來看下最終代碼 1public int openLock(String[] deadends, String target) { 2 Set<String> set = new HashSet<>(Arrays.asList(deadends)); 3 //開始遍歷的字符串是"0000",相當(dāng)于根節(jié)點 4 String startStr = "0000"; 5 if (set.contains(startStr)) 6 return -1; 7 //創(chuàng)建隊列 8 Queue<String> queue = new LinkedList<>(); 9 //記錄訪問過的節(jié)點 10 Set<String> visited = new HashSet<>(); 11 queue.offer(startStr); 12 visited.add(startStr); 13 //樹的層數(shù) 14 int level = 0; 15 while (!queue.isEmpty()) { 16 //每層的子節(jié)點個數(shù) 17 int size = queue.size(); 18 while (size-- > 0) { 19 //每個節(jié)點的值 20 String str = queue.poll(); 21 //對于每個節(jié)點中的4個數(shù)字分別進(jìn)行加1和減1,相當(dāng)于創(chuàng)建8個子節(jié)點,這八個子節(jié)點 22 //可以類比二叉樹的左右子節(jié)點 23 for (int i = 0; i < 4; i++) { 24 char ch = str.charAt(i); 25 //strAdd表示加1的結(jié)果,strSub表示減1的結(jié)果 26 String strAdd = str.substring(0, i) + (ch == '9' ? 0 : ch - '0' + 1) + str.substring(i + 1); 27 String strSub = str.substring(0, i) + (ch == '0' ? 9 : ch - '0' - 1) + str.substring(i + 1); 28 //如果找到直接返回 29 if (str.equals(target)) 30 return level; 31 //不能包含死亡數(shù)字也不能包含訪問過的字符串 32 if (!visited.contains(strAdd) && !set.contains(strAdd)) { 33 queue.offer(strAdd); 34 visited.add(strAdd); 35 } 36 if (!visited.contains(strSub) && !set.contains(strSub)) { 37 queue.offer(strSub); 38 visited.add(strSub); 39 } 40 } 41 } 42 //當(dāng)前層訪問完了,到下一層,層數(shù)要加1 43 level++; 44 } 45 return -1; 46}
實際上并不是一棵樹,但我們可以把它想象成為一棵樹,就像圖的BFS遍歷一樣,我們還需要使用一個變量來記錄訪問過的節(jié)點,如果被訪問過之后,下次就不能再訪問了。
|