You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
. The wheels can rotate freely and wrap around: for example we can turn '9'
to be '0'
, or '0'
to be '9'
. Each move consists of turning one wheel one slot.
The lock initially starts at '0000'
, a string representing the state of the 4 wheels.
You are given a list of deadends
dead ends, meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you will be unable to open it.
Given a target
representing the value of the wheels that will unlock the lock, return the minimum total number of turns required to open the lock, or -1 if it is impossible.
Example 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".
Example 2:
Input: deadends = ["8888"], target = "0009" Output: 1 Explanation: We can turn the last wheel in reverse to move from "0000" -> "0009".
Example 3:
Input: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888" Output: -1 Explanation: We can't reach the target without getting stuck.
Example 4:
Input: deadends = ["0000"], target = "8888" Output: -1
Note:
- The length of
deadends
will be in the range[1, 500]
. target
will not be in the listdeadends
.- Every string in
deadends
and the stringtarget
will be a string of 4 digits from the 10,000 possibilities'0000'
to'9999'
.
打开转盘锁。
题意是给一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/open-the-lock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路是 BFS。还是用经典的 BFS 模板做,跟岛屿一类的题其实是异曲同工的。因为锁的初始数字为 0000,所以可以将 0000 加入 queue。同时这道题需要创建两个 hashset,一个来记录到底遍历了那些组合,以节省时间,另一个以记录那些 deadends,避免被锁死。对于每一个当前组合,因为数字有 4 位,每次只能转动一个数字,所以每次遍历的时候,是可以得到前后两个数字的。举个例子,比如开始的时候是 0000,此时转动第一位,可以得到 1000 或者 9000。需要把这两个数字都加入 queue 参与下一轮的遍历。但是如果这其中有任何一个数字是 deadends 里面的数字,在他从 queue 中被弹出的时候则不需要做任何处理,直接丢弃即可。
时间约等于O(1) - 因为只有 10000 种组合,不过注意每种组合出现次数不止一次
空间O(n)
Java实现
1 class Solution { 2 public int openLock(String[] deadends, String target) { 3 Queue<String> queue = new LinkedList<>(); 4 HashSet<String> deads = new HashSet<>(Arrays.asList(deadends)); 5 HashSet<String> visited = new HashSet<>(); 6 queue.offer("0000"); 7 visited.add("0000"); 8 int level = 0; 9 while (!queue.isEmpty()) { 10 int size = queue.size(); 11 while (size > 0) { 12 String cur = queue.poll(); 13 if (deads.contains(cur)) { 14 size--; 15 continue; 16 } 17 if (cur.equals(target)) { 18 return level; 19 } 20 StringBuilder sb = new StringBuilder(cur); 21 for (int i = 0; i < 4; i++) { 22 char c = sb.charAt(i); 23 String s1 = sb.substring(0, i) + (c == '9' ? 0 : c - '0' + 1) + sb.substring(i + 1); 24 String s2 = sb.substring(0, i) + (c == '0' ? 9 : c - '0' - 1) + sb.substring(i + 1); 25 if (!visited.contains(s1) && !deads.contains(s1)) { 26 queue.offer(s1); 27 visited.add(s1); 28 } 29 if (!visited.contains(s2) && !deads.contains(s2)) { 30 queue.offer(s2); 31 visited.add(s2); 32 } 33 } 34 size--; 35 } 36 level++; 37 } 38 return -1; 39 } 40 }