​LeetCode刷题实战499:迷宫III

共 4365字,需浏览 9分钟

 ·

2022-01-19 10:47

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 迷宫III,我们先来看题面:
https://leetcode-cn.com/problems/the-maze-iii/

There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up (u), down (d), left (l) or right ®, but it won’t stop rolling until hitting a wall. When the ball stops, it could choose the next direction. There is also a hole in this maze. The ball will drop into the hole if it rolls on to the hole.

Given the ball position, the hole position and the maze, find out how the ball could drop into the hole by moving the shortest distance. The distance is defined by the number of empty spaces traveled by the ball from the start position (excluded) to the hole (included). Output the moving directions by using ‘u’, ‘d’, ‘l’ and ‘r’. Since there could be several different shortest ways, you should output the lexicographically smallest way. If the ball cannot reach the hole, output “impossible”.

The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the borders of the maze are all walls. The ball and the hole coordinates are represented by row and column indexes.



由空地和墙组成的迷宫中有一个球。球可以向上(u)下(d)左(l)右(r)四个方向滚动,但在遇到墙壁前不会停止滚动。当球停下时,可以选择下一个方向。迷宫中还有一个洞,当球运动经过洞时,就会掉进洞里。

给定球的起始位置,目的地和迷宫,找出让球以最短距离掉进洞里的路径。距离的定义是球从起始位置(不包括)到目的地(包括)经过的空地个数。通过'u', 'd', 'l' 和 'r'输出球的移动方向。由于可能有多条最短路径, 请输出字典序最小的路径。如果球无法进入洞,输出"impossible"。

迷宫由一个0和1的二维数组表示。1表示墙壁,0表示空地。你可以假定迷宫的边缘都是墙壁。起始位置和目的地的坐标通过行号和列号给出。

示例                         


解题

https://www.cnblogs.com/grandyang/p/6746528.html

这道题在之前的两道The Maze II和The Maze的基础上又做了些改变,在路径中间放了个陷阱,让球在最小步数内滚到陷阱之中,此时返回的并不是最小步数,而是滚动的方向,用u, r, d, l 这四个字母来分别表示上右下左,而且在步数相等的情况下,让我们返回按字母排序小的答案。相对于迷宫二那题来说,难度是增加了一些,但我们还是可以借鉴之前那道题的思路,我们还是需要用一个二位数组dists,其中dists[i][j]表示到达(i,j)这个位置时需要的最小步数,我们都初始化为整型最大值,在后在遍历的过程中不断用较小值来更新每个位置的步数值。我们还需要用一个哈希表来建立每个位置跟滚到该位置的方向字符串之间的映射,这里我们用一个trick,将二维坐标转(i,j)为一个数字i*n+j,这实际上就是把二维数组拉成一维数组的操作,matlab中很常见的操作。还有需要注意的是,一滚到底的操作需要稍作修改,之前我们都是一直滚到墙里面或者界外才停止,然后做退一步处理,就是小球能滚到的位置,这里我们滚的时候要判断陷阱,如果滚到了陷阱,那么我们也停下来,注意这时候不需要做后退一步处理。然后我们还是比较当前步数是否小于dists中的原有步数,小于的话就更新dists,然后更新哈希表中的映射方向字符串,然后对于不是陷阱的点,我们加入队列queue中继续滚。另一点跟迷宫二不同的之处在于,这里还要处理另一种情况,就是当最小步数相等的时候,并且新的滚法的方向字符串的字母顺序要小于原有的字符串的时候,我们也需要更新哈希表的映射,并且判断是否需要加入队列queue中,参见代码如下:

class Solution {
public:
    string findShortestWay(vector<vector<int>>& maze, vector<int>& ball, vector<int>& hole) {
        int m = maze.size(), n = maze[0].size();
        vector<vector<int>> dists(m, vector<int>(n, INT_MAX));
        vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}};
        vector<char> way{'l','u','r','d'};
        queueint, int>> q;
        unordered_map<int, string> u;
        dists[ball[0]][ball[1]] = 0;
        q.push({ball[0], ball[1]});
        while (!q.empty()) {
            auto t = q.front(); q.pop();
            for (int i = 0; i < 4; ++i) {
                int x = t.first, y = t.second, dist = dists[x][y];
                string path = u[x * n + y];
                while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == 0 && (x != hole[0] || y != hole[1])) {
                    x += dirs[i][0]; y += dirs[i][1]; ++dist;
                }
                if (x != hole[0] || y != hole[1]) {
                    x -= dirs[i][0]; y -= dirs[i][1]; --dist;
                }
                path.push_back(way[i]);
                if (dists[x][y] > dist) {
                    dists[x][y] = dist;
                    u[x * n + y] = path;
                    if (x != hole[0] || y != hole[1]) q.push({x, y});
                } else if (dists[x][y] == dist && u[x * n + y].compare(path) > 0) {
                    u[x * n + y] = path;
                    if (x != hole[0] || y != hole[1]) q.push({x, y});
                }
            }
        }
        string res = u[hole[0] * n + hole[1]];
        return res.empty() ? "impossible" : res;
    }
};


好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:


LeetCode1-480题汇总,希望对你有点帮助!

LeetCode刷题实战481:神奇字符串

LeetCode刷题实战482:密钥格式化

LeetCode刷题实战483:最小好进制

LeetCode刷题实战484:寻找排列

LeetCode刷题实战485:最大连续 1 的个数

LeetCode刷题实战486:预测赢家

LeetCode刷题实战487:最大连续1的个数 II

LeetCode刷题实战488:祖玛游戏

LeetCode刷题实战489:扫地机器人

LeetCode刷题实战490:迷宫

LeetCode刷题实战491:递增子序列

LeetCode刷题实战492:构造矩形

LeetCode刷题实战493:翻转对

LeetCode刷题实战494:目标和

LeetCode刷题实战495:提莫攻击

LeetCode刷题实战496:下一个更大元素 I

LeetCode刷题实战497:非重叠矩形中的随机点

LeetCode刷题实战498:对角线遍历


浏览 13
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报