[LeetCode] 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 (r), 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.

Example 1

Input 1: a maze represented by a 2D array

0 0 0 0 0
1 1 0 0 1
0 0 0 0 0
0 1 0 0 1
0 1 0 0 0

Input 2: ball coordinate (rowBall, colBall) = (4, 3)
Input 3: hole coordinate (rowHole, colHole) = (0, 1)

Output: "lul"
Explanation: There are two shortest ways for the ball to drop into the hole.
The first way is left -> up -> left, represented by "lul".
The second way is up -> left, represented by 'ul'.
Both ways have shortest distance 6, but the first way is lexicographically smaller because 'l' < 'u'. So the output is "lul".

 

Example 2

Input 1: a maze represented by a 2D array

0 0 0 0 0
1 1 0 0 1
0 0 0 0 0
0 1 0 0 1
0 1 0 0 0

Input 2: ball coordinate (rowBall, colBall) = (4, 3)
Input 3: hole coordinate (rowHole, colHole) = (3, 0)
Output: "impossible"
Explanation: The ball cannot reach the hole.

 

Note:

  1. There is only one ball and one hole in the maze.
  2. Both the ball and hole exist on an empty space, and they will not be at the same position initially.
  3. The given maze does not contain border (like the red rectangle in the example pictures), but you could assume the border of the maze are all walls.
  4. The maze contains at least 2 empty spaces, and the width and the height of the maze won't exceed 30.

 

這道題在之前的兩道The Maze IIThe 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'};
        queue<pair<int, 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;
    }
};

 

下面這種寫法是DFS的解法,可以看出來思路基本上跟上面的解法沒有啥區別,寫法上稍有不同,參見代碼如下:

 

解法二:

class Solution {
public:
    vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}};
    vector<char> way{'l','u','r','d'};
    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));
        unordered_map<int, string> u;
        dists[ball[0]][ball[1]] = 0;
        helper(maze, ball[0], ball[1], hole, dists, u);
        string res = u[hole[0] * n + hole[1]];
        return res.empty() ? "impossible" : res;
    }
    void helper(vector<vector<int>>& maze, int i, int j, vector<int>& hole, vector<vector<int>>& dists, unordered_map<int, string>& u) {
        if (i == hole[0] && j == hole[1]) return;
        int m = maze.size(), n = maze[0].size();
        for (int k = 0; k < 4; ++k) {
            int x = i, y = j, 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[k][0]; y += dirs[k][1]; ++dist;
            }
            if (x != hole[0] || y != hole[1]) {
                x -= dirs[k][0]; y -= dirs[k][1]; --dist;
            }
            path.push_back(way[k]);
            if (dists[x][y] > dist) {
                dists[x][y] = dist;
                u[x * n + y] = path;
                helper(maze, x, y, hole, dists, u);
            } else if (dists[x][y] == dist && u[x * n + y].compare(path) > 0) {
                u[x * n + y] = path;
                helper(maze, x, y, hole, dists, u);
            }
        }
    }
};

 

類似題目:

The Maze II

The Maze

 

參考資料:

https://discuss.leetcode.com/topic/77116/bfs-solution-using-a-queue

https://discuss.leetcode.com/topic/77074/clear-java-accepted-dfs-solution-with-explanation

https://discuss.leetcode.com/topic/77474/similar-to-the-maze-ii-easy-understanding-java-bfs-solution

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM