leetcode752-打开转盘锁

原题

你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有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

提示:

  1. 死亡列表 deadends 的长度范围为 [1, 500]。
  2. 目标数字 target 不会在 deadends 之中。
  3. 每个 deadends 和 target 中的字符串的数字会在 10,000 个可能的情况 ‘0000’ 到 ‘9999’ 中产生。

解法

思想

其实是一个树的BFS搜索问题:

每层示意图

用Queue来得到每层的节点。

主要需要注意的地方有:

  • 为了避免重复的节点进入队列,可以使用数组记录是否出现过,或是用HashSet记录出现过的节点。
  • 当遇到死亡数字数组中的元素时也不能将该元素添加至队列中。
  • 当搜索到题目要求的元素时,为了得到当前层数,有两种方法:
    1. 用一个数据结构表示节点,记录节点的值和层数。
    2. 每层元素入队列之后再加入一个null元素,每次遍历到null元素即可知道遍历完了了一层。

代码

我一开始是这样写的:

//节点的数据结构,需要记录层数
class Node{
    public String value;
    public int count;
    public Node(String value,int count){
        this.value = value;
        this.count = count;
    }
}

class Solution {
    public int openLock(String[] deadends, String target) {
        //如果死亡数组中存在0000直接返回-1
        if(arrayContains(deadends,"0000")) return -1;
        //标记数组用于记录哪些数字出现过
        int[] mark = new int[10000];
        //0000出现过
        mark[0] = 1;

        Queue<Node> queue = new LinkedList<Node>();
        queue.offer(new Node("0000",0));

        while(!queue.isEmpty()){
            //获取队列头
            Node node = queue.poll();
            if(node.value.equals(target)) return node.count;
            else {
                char[] charArray = node.value.toCharArray();
                for(int i = 0;i<4;i++) {
                    //位于第i位的数字+1,如果是9变成0
                    char[] plusOneCharArray = Arrays.copyOf(charArray,charArray.length);
                    plusOneCharArray[i] = (char) (charArray[i]=='9'?'0':charArray[i]+1);
                    String plusOne = String.valueOf(plusOneCharArray);
                    if(plusOne.equals(target)) 
                        return node.count+1;
                    //没有出现过且不在死亡数字中才添加至队列中
                    if((!arrayContains(deadends, plusOne))&&mark[Integer.valueOf(plusOne)]==0) {
                        queue.offer(new Node(plusOne,node.count+1));
                        mark[Integer.valueOf(plusOne)] = 1;
                    }
                    //位于第i位的数字-1,如果是0变成9                
                    char[] minusOneCharArray = Arrays.copyOf(charArray,charArray.length);
                    minusOneCharArray[i] = (char) (charArray[i]=='0'?'9':charArray[i]-1);
                    String minusOne = String.valueOf(minusOneCharArray);
                    if(minusOne.equals(target)) 
                        return node.count+1;
                    //没有出现过且不在死亡数字中才添加至队列中
                    if((!arrayContains(deadends, minusOne))&&mark[Integer.valueOf(minusOne)]==0) {
                        queue.offer(new Node(minusOne,node.count+1));
                        mark[Integer.valueOf(minusOne)] = 1;
                    }

                }
            }
        }

        return -1;
    }

    //遍历数组,用于检测死亡数字中是否存在指定的数字
    public boolean arrayContains(String[] stringArray,String toFind) {
        for(String i:stringArray) {
            if(i.equals(toFind)) return true;
        }
        return false;
    }
}

然后发现上面这种方法需要的时间贼久,最后强行理解了一下发现问题主要出在检测死亡数组中是否存在指定数字的时候,时间开销太高了。

最后还是换成了用HashSet检测死亡数组中是否存在指定的数字:

class Node{
    public String value;
    public int count;
    public Node(String value,int count){
        this.value = value;
        this.count = count;
    }
}

class Solution {
    public int openLock(String[] deadends, String target) {
        //将死亡数字全部加进一个HashSet中
        Set<String> set = new HashSet<String>();
        for(String i:deadends) {
            if(i.equals("0000"))
                return -1;
            set.add(i);
        }

        int[] mark = new int[10000];
        mark[0] = 1;
        Queue<Node> queue = new LinkedList<Node>();
        queue.offer(new Node("0000",0));

        while(!queue.isEmpty()){
            Node node = queue.poll();
            if(node.value.equals(target)) return node.count;
            else {
                char[] charArray = node.value.toCharArray();
                for(int i = 0;i<4;i++) {
                    char[] plusOneCharArray = Arrays.copyOf(charArray,charArray.length);
                    plusOneCharArray[i] = (char) (charArray[i]=='9'?'0':charArray[i]+1);
                    String plusOne = String.valueOf(plusOneCharArray);
                    if(plusOne.equals(target)) 
                        return node.count+1;
                    if((!set.contains(plusOne))&&mark[Integer.valueOf(plusOne)]==0) {
                        queue.offer(new Node(plusOne,node.count+1));
                        mark[Integer.valueOf(plusOne)] = 1;
                    }

                    char[] minusOneCharArray = Arrays.copyOf(charArray,charArray.length);
                    minusOneCharArray[i] = (char) (charArray[i]=='0'?'9':charArray[i]-1);
                    String minusOne = String.valueOf(minusOneCharArray);
                    if(minusOne.equals(target)) 
                        return node.count+1;
                    if((!set.contains(minusOne))&&mark[Integer.valueOf(minusOne)]==0) {
                        queue.offer(new Node(minusOne,node.count+1));
                        mark[Integer.valueOf(minusOne)] = 1;
                    }

                }
            }
        }

        return -1;
    }
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/leetcode752-%e6%89%93%e5%bc%80%e8%bd%ac%e7%9b%98%e9%94%81/

(0)
彭晨涛彭晨涛管理者
上一篇 2019年12月6日
下一篇 2019年12月10日

相关推荐

  • leetcode1371-每个元音包含偶数次的最长子字符串

    原题 给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 'a','e','i','o','u' ,在子字符串中都恰好出现了偶数次。 示例 1: 输入…

    算法 2020年5月20日
    01600
  • leetcode394-字符串解码

    原题 给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意…

    算法 2019年12月13日
    090
  • 用一个栈实现另一个栈的排序

    原题(来源牛客网) 一个栈中元素的类型为整型,现在想将该栈从顶到底按从大到小的顺序排序,只许申请一个栈。除此之外,可以申请新的变量,但不能申请额外的数据结构。如何完成排序? 解法 …

    算法 2020年4月20日
    02110
  • leetcode23-合并K个排序链表

    原题 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] 输出: 1->1->2->3->…

    算法 2020年2月4日
    0170
  • 程序员面试金典08.01-三步问题

    原题(来源Leetcode) 三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模…

    算法 2020年6月19日
    04800
  • leetcode331-验证二叉树的前序序列化

    原题 序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。 _9_ / \ 3 2…

    算法 2020年1月26日
    0100
  • 剑指offer05-替换空格

    原题(来源Leetcode) 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 示例1: 输入: s = "We are happy." 输出: "We%20are%2…

    算法 2020年4月5日
    0110
  • leetcode994-腐烂的橘子

    原题 在给定的网格中,每个单元格可以有以下三个值之一: 值 0 代表空单元格;值 1 代表新鲜橘子;值 2 代表腐烂的橘子。每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜…

    2020年3月4日
    0100
  • leetcode15-三数之和

    原题 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 注意:…

    算法 2020年5月4日
    0190
  • leetcode622-设计循环队列

    设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是…

    算法 2019年11月24日
    0130

发表回复

登录后才能评论