leet_code_752.打开转盘锁(广度)

简介: leet_code_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


提示:

死亡列表 deadends 的长度范围为 [1, 500]。

目标数字 target 不会在 deadends 之中。

每个 deadends 和 target 中的字符串的数字会在 10,000 个可能的情况 ‘0000’ 到 ‘9999’ 中产生。


代码实现

package com.honsupply.api.core.util.logger;
import java.util.*;
public class Test {
    public static void main(String[] args) {
        String[] deadends = {"0201", "0101", "0102", "1212", "2002"};
        String target = "0202";
        System.out.println(openLock(deadends, target));
    }
    /** 解决转盘锁的问题
     * 本题为自己的思路,效率不是很高,如需更有答案,请移步力扣,搜索"打开转盘锁"。
     * 解决问题的思想:每次可以转动一个,转动一次步长为1,第一次转动可以为"1000","1010","9000","0900"...
     * 将一次可转动的放到队列中,然后插入一个null值,然后基于前一次的基础上转动第二下
     * 遇到第一个插入的null时代表第一轮循环完毕,则步数+1,然后插入一个新的null值,代表在此之前的均为前一次步数可达的范围。
     */
    private static int openLock(String[] deadends, String target){
        if(target.equals("0000")) return 0;
        Set<String> set = new HashSet<>();
        Collections.addAll(set, deadends);
        // 定义出现过的方案,以防重复,进入死循环
        Set<String> answerSet = new HashSet<>();
        answerSet.add("0000");
        Queue<String> queue = new LinkedList<>();
        queue.offer("0000");
        // 插入null值,用于计算步长
        queue.offer(null);
        int step = 0;
        // 如果队列不为空,则一直循环下去,如果为空,且未找到答案,则返回-1
        while(!queue.isEmpty()){
            // 取队列的第一个值
            String answer = queue.remove();
            // 遇见null,则步长+1
            if(answer == null){
                step ++;
                // 如果null后面还有数据,则插入一个新的null,标志一轮结束
                if(queue.peek() != null){
                    queue.offer(null);
                }
            // 匹配到正确的答案,返回步长
            }else if(answer.equals(target)){
                return step;
            // 当遇到deadends内的值时,则无需继续向下找,故跳出for循环
            }else if(!set.contains(answer)){
                // 每次可以转动第1.2.3.4的数值
                for (int i = 0; i < 4; i ++){
                    // 取当前位置的数字+1 or -1。
                    // 如果为9,+ 1 则变成0
                    // 如果为0,- 1 则变成9
                    int number = Integer.parseInt(answer.substring(i, i+1));
                    int nextNum = number == 9 ? 0 : number+1;
                    String next = answer.substring(0, i) + String.valueOf(nextNum) + answer.substring(i + 1, 4);
                    if(!answerSet.contains(next)){
                        queue.offer(next);
                        answerSet.add(next);
                    }
                    int prevNum = number == 0 ? 9 : number-1;
                    String prev = answer.substring(0, i) + String.valueOf(prevNum) + answer.substring(i + 1, 4);
                    if(!answerSet.contains(prev)){
                        queue.offer(prev);
                        answerSet.add(prev);
                    }
                }
            }
        }
        return -1;
    }
}


目录
相关文章
|
6月前
|
SQL 算法 vr&ar
☆打卡算法☆LeetCode 182. 查找重复的电子邮箱 算法解析
☆打卡算法☆LeetCode 182. 查找重复的电子邮箱 算法解析
☆打卡算法☆LeetCode 182. 查找重复的电子邮箱 算法解析
|
6月前
|
存储 算法 vr&ar
☆打卡算法☆LeetCode 165. 比较版本号 算法解析
☆打卡算法☆LeetCode 165. 比较版本号 算法解析
|
6月前
|
算法 vr&ar 图形学
☆打卡算法☆LeetCode 174. 地下城游戏 算法解析
☆打卡算法☆LeetCode 174. 地下城游戏 算法解析
|
前端开发 C++
#yyds干货盘点# 【Vs code工作记录二】如何解决vs code波浪线
#yyds干货盘点# 【Vs code工作记录二】如何解决vs code波浪线
151 0
#yyds干货盘点# 【Vs code工作记录二】如何解决vs code波浪线
|
测试技术 C++
【LeetCode752】打开转盘锁(BFS)
【LeetCode752】打开转盘锁(BFS) 每个节点有8个孩子节点,如题目给的第二个测试用例,start=0000时,4个位置分别可以向上转or向下转,得到1000、9000、0100、0900等8种情况。即这是一棵八叉树。即求解从start数字到target的最短路径。为了找到最小旋转次次数,利用BFS逐层查找,遇到target则返回树高度(层数)。
134 0
【LeetCode752】打开转盘锁(BFS)
☆打卡算法☆LeetCode 130. 被围绕的区域 算法解析
“给定一个矩阵,矩阵由字符X和O组成,找出所有被X包围的区域,将区域内的所有O替换成X。”
☆打卡算法☆LeetCode 45、跳跃游戏II 算法解析
“给定一个非负整数数组,数组中每个元素代表可以跳跃的最大高度,使用最少的跳跃次数跳到数组最后一个位置。”
☆打卡算法☆LeetCode 55、跳跃游戏 算法解析
“给定一个非负整数数组,数组中每个元素代表可以跳跃的长度,判断能否达到最后一个下标。”
|
存储 算法
☆打卡算法☆LeetCode 99、恢复二叉搜索树 算法解析
“给定二叉搜索树的根节点root,该树中有错误的节点,请在不改变结构的情况下,恢复这棵树。”
|
算法 索引
☆打卡算法☆LeetCode 35、搜索插入位置 算法解析
“给定一个排序好的整数数组和一个目标值,在数组中找到目标值,返回其索引。如果目标值不存在数组中,就将目标值插入数组中按顺序的正确位置中。”