Welcome to Subscribe On Youtube
2617. Minimum Number of Visited Cells in a Grid
Description
You are given a 0-indexed m x n
integer matrix grid
. Your initial position is at the top-left cell (0, 0)
.
Starting from the cell (i, j)
, you can move to one of the following cells:
- Cells
(i, k)
withj < k <= grid[i][j] + j
(rightward movement), or - Cells
(k, j)
withi < k <= grid[i][j] + i
(downward movement).
Return the minimum number of cells you need to visit to reach the bottom-right cell (m - 1, n - 1)
. If there is no valid path, return -1
.
Example 1:
Input: grid = [[3,4,2,1],[4,2,3,1],[2,1,0,0],[2,4,0,0]] Output: 4 Explanation: The image above shows one of the paths that visits exactly 4 cells.
Example 2:
Input: grid = [[3,4,2,1],[4,2,1,1],[2,1,1,0],[3,4,1,0]] Output: 3 Explanation: The image above shows one of the paths that visits exactly 3 cells.
Example 3:
Input: grid = [[2,1,0],[1,0,0]] Output: -1 Explanation: It can be proven that no path exists.
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 105
1 <= m * n <= 105
0 <= grid[i][j] < m * n
grid[m - 1][n - 1] == 0
Solutions
Solution 1: Priority Queue
Let’s denote the number of rows of the grid as $m$ and the number of columns as $n$. Define $dist[i][j]$ to be the shortest distance from the coordinate $(0, 0)$ to the coordinate $(i, j)$. Initially, $dist[0][0]=1$ and $dist[i][j]=-1$ for all other $i$ and $j$.
For each grid $(i, j)$, it can come from the grid above or the grid on the left. If it comes from the grid above $(i’, j)$, where $0 \leq i’ \lt i$, then $(i’, j)$ must satisfy $grid[i’][j] + i’ \geq i$. We need to select from these grids the one that is closest.
Therefore, we maintain a priority queue (min-heap) for each column $j$. Each element of the priority queue is a pair $(dist[i][j], i)$, which represents that the shortest distance from the coordinate $(0, 0)$ to the coordinate $(i, j)$ is $dist[i][j]$. When we consider the coordinate $(i, j)$, we only need to take out the head element $(dist[i’][j], i’)$ of the priority queue. If $grid[i’][j] + i’ \geq i$, we can move from the coordinate $(i’, j)$ to the coordinate $(i, j)$. At this time, we can update the value of $dist[i][j]$, that is, $dist[i][j] = dist[i’][j] + 1$, and add $(dist[i][j], i)$ to the priority queue.
Similarly, we can maintain a priority queue for each row $i$ and perform a similar operation.
Finally, we can obtain the shortest distance from the coordinate $(0, 0)$ to the coordinate $(m - 1, n - 1)$, that is, $dist[m - 1][n - 1]$, which is the answer.
The time complexity is $O(m \times n \times \log (m \times n))$ and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the grid, respectively.
-
class Solution { public int minimumVisitedCells(int[][] grid) { int m = grid.length, n = grid[0].length; int[][] dist = new int[m][n]; PriorityQueue<int[]>[] row = new PriorityQueue[m]; PriorityQueue<int[]>[] col = new PriorityQueue[n]; for (int i = 0; i < m; ++i) { Arrays.fill(dist[i], -1); row[i] = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); } for (int i = 0; i < n; ++i) { col[i] = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); } dist[0][0] = 1; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { while (!row[i].isEmpty() && grid[i][row[i].peek()[1]] + row[i].peek()[1] < j) { row[i].poll(); } if (!row[i].isEmpty() && (dist[i][j] == -1 || row[i].peek()[0] + 1 < dist[i][j])) { dist[i][j] = row[i].peek()[0] + 1; } while (!col[j].isEmpty() && grid[col[j].peek()[1]][j] + col[j].peek()[1] < i) { col[j].poll(); } if (!col[j].isEmpty() && (dist[i][j] == -1 || col[j].peek()[0] + 1 < dist[i][j])) { dist[i][j] = col[j].peek()[0] + 1; } if (dist[i][j] != -1) { row[i].offer(new int[] {dist[i][j], j}); col[j].offer(new int[] {dist[i][j], i}); } } } return dist[m - 1][n - 1]; } }
-
class Solution { public: int minimumVisitedCells(vector<vector<int>>& grid) { int m = grid.size(), n = grid[0].size(); vector<vector<int>> dist(m, vector<int>(n, -1)); using pii = pair<int, int>; priority_queue<pii, vector<pii>, greater<pii>> row[m]; priority_queue<pii, vector<pii>, greater<pii>> col[n]; dist[0][0] = 1; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { while (!row[i].empty() && grid[i][row[i].top().second] + row[i].top().second < j) { row[i].pop(); } if (!row[i].empty() && (dist[i][j] == -1 || row[i].top().first + 1 < dist[i][j])) { dist[i][j] = row[i].top().first + 1; } while (!col[j].empty() && grid[col[j].top().second][j] + col[j].top().second < i) { col[j].pop(); } if (!col[j].empty() && (dist[i][j] == -1 || col[j].top().first + 1 < dist[i][j])) { dist[i][j] = col[j].top().first + 1; } if (dist[i][j] != -1) { row[i].emplace(dist[i][j], j); col[j].emplace(dist[i][j], i); } } } return dist[m - 1][n - 1]; } };
-
class Solution: def minimumVisitedCells(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) dist = [[-1] * n for _ in range(m)] dist[0][0] = 1 row = [[] for _ in range(m)] col = [[] for _ in range(n)] for i in range(m): for j in range(n): while row[i] and grid[i][row[i][0][1]] + row[i][0][1] < j: heappop(row[i]) if row[i] and (dist[i][j] == -1 or dist[i][j] > row[i][0][0] + 1): dist[i][j] = row[i][0][0] + 1 while col[j] and grid[col[j][0][1]][j] + col[j][0][1] < i: heappop(col[j]) if col[j] and (dist[i][j] == -1 or dist[i][j] > col[j][0][0] + 1): dist[i][j] = col[j][0][0] + 1 if dist[i][j] != -1: heappush(row[i], (dist[i][j], j)) heappush(col[j], (dist[i][j], i)) return dist[-1][-1]
-
func minimumVisitedCells(grid [][]int) int { m, n := len(grid), len(grid[0]) dist := make([][]int, m) row := make([]hp, m) col := make([]hp, n) for i := range dist { dist[i] = make([]int, n) for j := range dist[i] { dist[i][j] = -1 } } dist[0][0] = 1 for i := 0; i < m; i++ { for j := 0; j < n; j++ { for len(row[i]) > 0 && grid[i][row[i][0].second]+row[i][0].second < j { heap.Pop(&row[i]) } if len(row[i]) > 0 && (dist[i][j] == -1 || row[i][0].first+1 < dist[i][j]) { dist[i][j] = row[i][0].first + 1 } for len(col[j]) > 0 && grid[col[j][0].second][j]+col[j][0].second < i { heap.Pop(&col[j]) } if len(col[j]) > 0 && (dist[i][j] == -1 || col[j][0].first+1 < dist[i][j]) { dist[i][j] = col[j][0].first + 1 } if dist[i][j] != -1 { heap.Push(&row[i], pair{dist[i][j], j}) heap.Push(&col[j], pair{dist[i][j], i}) } } } return dist[m-1][n-1] } type pair struct { first int second int } type hp []pair func (a hp) Len() int { return len(a) } func (a hp) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a hp) Less(i, j int) bool { return a[i].first < a[j].first || (a[i].first == a[j].first && a[i].second < a[j].second) } func (a *hp) Push(x any) { *a = append(*a, x.(pair)) } func (a *hp) Pop() any { l := len(*a); t := (*a)[l-1]; *a = (*a)[:l-1]; return t }