<1> 迷宫问题

这篇博客介绍了一种使用广度优先搜索(BFS)算法来寻找迷宫中从球的起始位置到洞的最短路径的方法。通过维护步数和路径字符串的二维数组,以及利用队列进行迭代,作者详细解释了如何在空地上模拟球的移动并更新步数和路径。最终,通过比较步数和路径字典序找到最短路径。此算法相较于深度优先搜索(DFS)有更高的效率。
摘要由CSDN通过智能技术生成

1.题目描述

在这里插入图片描述

在这里插入图片描述

2. 题解

    func findShortestWay(_ maze: [[Int]], _ ball: [Int], _ hole: [Int]) -> String {
        // 行:row   列:column
        let row = maze.count
        let column = maze[0].count
        // 1.用一个行,列相同的数组,维护步数
        var steps = [[Int]](repeating: [Int](repeating: Int.max, count: column), count: row)
        // 2.用一个行,列相同的数组,维护表示路径的字符串
        var pathStrs = [[String]](repeating: [String](repeating: "impossible", count: column), count: row)
        
        // 3.用一个元组,表示方向和字符
        let dirs = [(-1,0,"u"),(1,0,"d"),(0,-1,"l"),(0,1,"r")]
        
        // 4.用一个数组,来表示队列的数据结构,里面装的是数组,表示当前的x,y坐标,初始值为球出发的坐标
        var queue = [[ball[0],ball[1]]]
        // 5.初始化球出发的坐标时候,步数和对应的路径字符,步数为0,路径为空字符
        steps[ball[0]][ball[1]] = 0
        pathStrs[ball[0]][ball[1]] = ""
        
        while !queue.isEmpty {
            // 取出当前球所在的坐标
            let ballPosition = queue.removeFirst()
            // 如果当前球的位置在洞的位置,那么结束,后面再继续走,就是浪费时间和性能了
            if ballPosition[0] == hole[0] && ballPosition[1] == hole[1] {
                return pathStrs[ballPosition[0]][ballPosition[1]]
            }
            
            // 能来到这里,说明球所在的位置不是洞的位置
            // 模拟球走的4个方向
            for (x,y,str) in dirs {
                // 走的下一个方向
                var nextRow = ballPosition[0] + x
                var nextColumn = ballPosition[1] + y
                
                // 当前的位置的步数
                var step = steps[ballPosition[0]][ballPosition[1]]
                // 当前的字典序
                var dictSequence = pathStrs[ballPosition[0]][ballPosition[1]]
                
                // 假设朝着当前方向走,是有效(1.没有越界 2.是空地);
                // 就继续朝着这个方向走,看能走到多少步停下(1.越界 2.撞到墙 3.进洞)
                // 在横冲直撞的过程,看下上一个位置是否是洞的位置:!(nextRow - x == hole[0] && nextColumn - y == hole[1])
                while nextRow >= 0 && nextRow < row && nextColumn >= 0 && nextColumn < column && maze[nextRow][nextColumn] == 0 && !(nextRow - x == hole[0] && nextColumn - y == hole[1]) {
                    nextRow = nextRow + x
                    nextColumn = nextColumn + y
                    // 每继续走一步,步数增加1
                    step = step + 1
                }
                
                // 到了这里,说明上面一步中,遇到了不符合条件的坐标
                // 回退一步,就是最后一个符合坐标的位置了,我们用lastPosition来描述
                nextRow = nextRow - x
                nextColumn = nextColumn - y
                
                // 更新字典序
                dictSequence = dictSequence + str
                
                // 需要尝试重新记录(1.步数  2.方向字符)
                // 1.如果之前lastPosition位置的的步数数组中记录的步数比当前计算的步数大,需要更新
                // 2.如果步数相等,但是字典序更大,也要重新更新,因为我们要字典序最小的路径
                
                if steps[nextRow][nextColumn] > step || (steps[nextRow][nextColumn] == step && pathStrs[nextRow][nextColumn] > dictSequence) {
                    
                    steps[nextRow][nextColumn] = step
                    pathStrs[nextRow][nextColumn] = dictSequence
                    // 不在洞里,加入队列,作为下一轮的while循环的起点
                    if !(nextRow == hole[0] && nextColumn == hole[1]) {
                        queue.append([nextRow,nextColumn]) // 在这一轮的for循环里,理论上最多增加4个元素
                    }
                }
            }
        }
        return pathStrs[hole[0]][hole[1]]
    }

3.思路

  1. 计算最短路径的,用BFS思路会比DFS快几十倍,记住这个套路就行,理解因人而异。
  2. BFS离不开队列,入队,出队,在swift语言中,用数组就可以当做队列来使用
  3. 记忆化方法,在这里维护两个行、列相同的数组,分别用来记录步数、路径字符串
  4. 审题是要注意,这里我们可以把它想象成打台球,但是这里的台球不会反弹,因此在空地上,没有停下的时候,会继续走,我们步数是依然记录,但是方向只记录打台球“出杆”的方向(我们的台球只会“横冲直撞”)
  5. 队列入队的条件,当台球停下来的时候,只要台球不是进洞了,我们就入队。
  6. // 在横冲直撞的过程,看下上一个位置是否是洞的位置
 // 在横冲直撞的过程,看下上一个位置是否是洞的位置:!(nextRow - x == hole[0] && nextColumn - y == hole[1])
                while nextRow >= 0 && nextRow < row && nextColumn >= 0 && nextColumn < column && maze[nextRow][nextColumn] == 0 && !(nextRow - x == hole[0] && nextColumn - y == hole[1]) {
                    nextRow = nextRow + x
                    nextColumn = nextColumn + y
                    // 每继续走一步,步数增加1
                    step = step + 1
                }

4.提交结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值