diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index 4ab0293..9f3a636 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -3958,3 +3958,104 @@ func validPath(n int, edges [][]int, source int, destination int) bool { return ds.IsConnected(source, destination) } ``` + +## day55 2024-04-22 + +### 752. Open the Lock + +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. + +![0422NdMH16LLOOVH](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0422NdMH16LLOOVH.png) + +### 题解 + +本题题面非常有意思, 关键是怎么转化这道题. 首先思考如果只有两个转盘, 那么问题可以转化成在一个二维平面上从点(0,0)走到目标点的有障碍物最短路问题, 即在二维数组中, 从(0,0)走到目标点,每次只能向相邻方向移动一位, 同时有一些坐标是不能走得(可以理解为有障碍物). 对于这个问题, 无疑首先想到的就可以通过BFS求解. 将这个问题从二维扩展到四维, 因为每个转盘只有0-9 共10个数字, 所以每一维只需要10个数表示即可, 这样问题就变成了在一个10\*10\*10\*10的四维数组中, 从(0,0,0,0)走到目标点的最短路问题, 其中数组中有些位置是不可达的. 同样使用和二维数组中类似的BFS求解即可. + +### 代码 + +```go +func openLock(deadends []string, target string) int { + deadends_number := map[int]int{} + targetnumber,_ := strconv.Atoi(target) + + for _, value := range deadends { + number,_ := strconv.Atoi(value) + if number == 0{ + return -1 + } + deadends_number[number] = 1 + } + + pathmap := [][][][]int{} + for z := 0; z < 11; z++ { + second := [][][]int{} + for i := 0; i < 11; i++ { + three := [][]int{} + for j := 0; j < 11; j++ { + four := []int{} + for k := 0; k < 11; k++ { + _, exist := deadends_number[z*1000+i*100+j*10+k] + if exist { + four = append(four, 0) + } else { + four = append(four, 1) + } + } + three = append(three, four) + } + second = append(second, three) + } + pathmap = append(pathmap, second) + } + + queue := [][]int{{0, 0, 0, 0}} + pathmap[0][0][0][0] = 0 + depth := -1 + for len(queue) != 0 { + for _, way := range queue { + if way[0]*1000+way[1]*100+way[2]*10+way[3] == targetnumber{ + return depth+1 + } + for i := 0; i < 4; i++ { // 遍历四个维度 + original := way[i] // 保存原始值 + // 尝试向两个方向移动 + for _, diff := range []int{-1, 1} { + newIdx := original + diff + + // 处理边界情况 + if newIdx < 0 { + newIdx = 9 + } else if newIdx > 9 { + newIdx = 0 + } + + way[i] = newIdx // 更新当前维度 + + // 检查新位置是否可行 + if pathmap[way[0]][way[1]][way[2]][way[3]] == 1 { + queue = append(queue, []int{way[0], way[1], way[2], way[3]}) + pathmap[way[0]][way[1]][way[2]][way[3]] = 0 + } + + way[i] = original // 恢复原始值以便下一次循环使用 + } + } + queue = queue[1:] + } + depth++ + } + + return -1 +} + +``` + +### 总结 + +遇到题面看上去复杂的题目需要将题目的核心问题抽离出来. 若题目本身解决起来比较困难, 可以先尝试思考解决题目的一个子问题, 如降低维度, 减少数量, 再尝试推广到题目本身. 另外在数学中往往从一维到二维有很多不同点, 可能需要全新的工具和解决方式. 但从二维到更高维往往只是简单推广, 这也是为什么很多数学问题只证明二维的情况即可代表全部高维情况的原因.