算法—leetcode—752

426 阅读2分钟

题目

(752). 打开转盘锁

题目描述

你有一个带有四个圆形拨轮的转盘锁;每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ; 每个拨轮可以自由旋转:例如把'9'变为'0','0' 变为'9' ;每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为'0000' ,一个代表四个拨轮的数字的字符串。
列表deadends包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串target代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回-1。

示例

示例一

输入:["0201","0101","0102","1212","2002"] "0202"
输出:6

思路一

使用BFS
明确起点和终点

起点:”0000“ 终点:target

当前节点扩散的点:每个位置向上拨动或者向下拨动共有八种情景

死亡数字:遇到死亡数值直接掠过

优化:为防止重复遍历已经遍历的点,可以将遍历的节点存储起来,加入扩散的点时进行校验

代码

package leetcode

import (
    "strings"
)

// openLock
// 打开转盘锁
func openLock(deadends []string, target string) int {
    // 初始化一个队列
    queue := []string{"0000"}
    count := []int{0}
    deads := strings.Join(deadends, ",")
    
    // 记录已经穷举过的密码,防止走回头路
    visited := map[string]bool{"0000":true}
    
    // 将当前队列中的所有节点向周围扩散
    for i:=0; i<len(queue); i++ {
        cur := queue[i]
        number := count[i]
        // 校验是否达到终点
        if strings.Contains(deads, cur){
            continue
        }
        if cur==target {
            return number
        }
        
        // 将一个节点的相邻节点加入队列
        for j:=0; j<4; j++{
            up := plusOne(cur, j)
            if _, ok := visited[up];!ok{
                queue = append(queue, up)
                count = append(count, number+1)
                visited[up] = true
            }
            
            down := minusOne(cur, j)
            if _, ok := visited[down]; !ok{
                queue = append(queue, down)
                count = append(count, number+1)
                visited[down] = true
            }
        }
    }
    return -1
}

// openLockBFS
// 问题
// 1、会走回头路
// 2、没有对deadends的处理
func openLockBFS(target string) int {
    // 初始化一个队列
    queue := []string{"0000"}
    count := []int{1}
    
    // 将当前队列中的所有节点向周围扩散
    for i:=0; i<len(queue); i++ {
        cur := queue[i]
        number := count[i]
        // 校验是否达到终点
        if cur==target {
            return number
        }
        
        // 将一个节点的相邻节点加入队列
        for j:=0; j<4; j++{
            up := plusOne(cur, j)
            queue = append(queue, up)
            count = append(count, number+1)
            
            down := minusOne(cur, j)
            queue = append(queue, down)
            count = append(count, number+1)
        }
    }
    return 0
}

// plusOne
// 将s[j]向上拨动一次
func plusOne(s string, index int) string {
    data := []byte(s)
    if data[index] == 57 {
        data[index] = 48
    } else {
        data[index]++
    }
    return string(data)
}

// minusOne
// 将 s[i] 向下拨动一次
func minusOne(s string, index int) string {
    data := []byte(s)
    if data[index] == 48 {
        data[index] = 57
    } else {
        data[index]--
    }
    return string(data)
}

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/op…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

labuladong的算法小抄