题目地址:
https://leetcode.com/problems/minimum-cost-to-make-at-least-one-valid-path-in-a-grid/
给定一个 m m m行 n n n列的二维矩阵,每个元素是 1 ∼ 4 1\sim 4 1∼4之一, 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4分别代表右左下上四个方向。从 ( 0 , 0 ) (0,0) (0,0)这个位置出发,要走到 ( m − 1 , n − 1 ) (m-1,n-1) (m−1,n−1)这个位置,但是每一步只能按照格子里的方向走。允许改变若干个格子所代表的方向。问至少改变多少个格子可以使得从起点到终点是可达的。
这道题其实是个经典的双端队列BFS。将每个格子看成是图的顶点,相邻格子是有边相连接的。如果从顶点 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)到 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的实际方向和矩阵在 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)的数字所表示的方向相同,则令这条边的边权为 0 0 0,否则令其边权为 1 1 1。原题相当于在问,在此图中,从起点到终点的最短路长度是多少。由于边权只有 0 0 0和 1 1 1两种,所以可以用双端队列BFS来做。每次拓展的时候,如果是沿着边权 0 0 0的边走的,则插入队头,否则插入队尾。从队列里取元素的时候永远都从队头取。然后用堆优化的Dijkstra算法模板来写即可。具体详细思路参考https://blog.csdn.net/qq_46105170/article/details/114667171。代码如下:
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
public class Solution {
public int minCost(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[] d = {1, 0, -1, 0, 1};
// mapToD[i]表示d[i]所表示的方向在题目中的数字表示
int[] mapToD = {3, 2, 4, 1};
Deque<Integer> deque = new ArrayDeque<>();
int[][] dist = new int[m][n];
for (int[] row : dist) {
Arrays.fill(row, Integer.MAX_VALUE);
}
boolean[][] visited = new boolean[m][n];
deque.offerLast(0);
dist[0][0] = 0;
while (!deque.isEmpty()) {
int cur = deque.pollFirst();
if (visited[cur / n][cur % n]) {
continue;
}
int x = cur / n, y = cur % n;
// 终点第一次出队的时候,dist里存的就是最短路距离
if (x == m - 1 && y == n - 1) {
return dist[m - 1][n - 1];
}
visited[x][y] = true;
for (int i = 0; i < 4; i++) {
int nextX = x + d[i], nextY = y + d[i + 1];
if (!(0 <= nextX && nextX < m && 0 <= nextY && nextY < n)) {
continue;
}
int e = grid[x][y] == mapToD[i] ? 0 : 1;
if (!visited[nextX][nextY] && dist[nextX][nextY] > dist[x][y] + e) {
dist[nextX][nextY] = dist[x][y] + e;
if (e == 0) {
deque.offerFirst(nextX * n + nextY);
} else {
deque.offerLast(nextX * n + nextY);
}
}
}
}
return -1;
}
}
时空复杂度 O ( m n ) O(mn) O(mn)。
C++:
class Solution {
public:
struct Node {
int x, y, dist;
};
int minCost(vector<vector<int>>& g) {
int m = g.size(), n = g[0].size();
deque<Node> dq;
dq.push_back({0, 0, 0});
bool vis[m][n];
memset(vis, 0, sizeof vis);
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
while (dq.size()) {
auto t = dq.front();
dq.pop_front();
int x = t.x, y = t.y, dist = t.dist;
if (x == m - 1 && y == n - 1) return dist;
vis[x][y] = true;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (0 <= nx && nx < m && 0 <= ny && ny < n && !vis[nx][ny]) {
if (g[x][y] == i + 1)
dq.push_front({nx, ny, dist});
else
dq.push_back({nx, ny, dist + 1});
}
}
}
return -1;
}
};
时空复杂度一样。