The provided code implements a solution to the Minimum Obstacle Removal to Reach Corner problem in JavaScript using Dijkstra’s algorithm. The goal is to traverse a binary grid (where 0
represents a passable cell and 1
represents an obstacle) from the top-left corner (0, 0)
to the bottom-right corner (m-1, n-1)
while removing the minimum number of obstacles.
The solution begins by initializing the grid’s dimensions (m
and n
), and defining directional vectors for moving up, down, left, and right. A result
matrix is created, filled with Infinity
, to store the minimum obstacles removed to reach each cell, starting with result[0][0] = 0
. A priority queue (MinPriorityQueue
) is used to prioritize cells based on the number of obstacles removed.
The main loop processes cells from the queue. For each cell, its neighbors are evaluated to ensure they are within bounds. If a neighbor cell has a better path (fewer obstacles removed), its value in the result
matrix is updated, and it is added to the priority queue for further exploration.
Finally, the function returns the value at the bottom-right corner (result[m-1][n-1]
), representing the minimum obstacles removed to reach the destination. The code efficiently combines a priority queue and grid traversal to solve this pathfinding problem.
My Code:
codevar minimumObstacles = function(grid) {
let m = grid.length;
let n = grid[0].length;
let directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
let result = Array.from({ length: m }, () => new Array(n).fill(Infinity));
result[0][0] = 0;
let priorityQueue = new MinPriorityQueue({ priority: x => x.weight });
priorityQueue.enqueue({ weight: 0, position: [0, 0] });
while (!priorityQueue.isEmpty()) {
let { element } = priorityQueue.dequeue();
let { weight: obstaclesRemoved, position } = element;
let [i, j] = position;
for (let direction of directions) {
let x = i + direction[0];
let y = j + direction[1];
if (x < 0 || x >= m || y < 0 || y >= n) {
continue;
}
let additionalObstacle = grid[x][y] === 1 ? 1 : 0;
if (obstaclesRemoved + additionalObstacle < result[x][y]) {
result[x][y] = obstaclesRemoved + additionalObstacle;
priorityQueue.enqueue({
weight: obstaclesRemoved + additionalObstacle,
position: [x, y]
});
}
}
}
return result[m - 1][n - 1];
};
Mastering Minimum Obstacle Removal in JavaScript
Pathfinding problems are a cornerstone of algorithmic challenges, and LeetCode’s Minimum Obstacle Removal to Reach Corner is an excellent example. This problem leverages Dijkstra’s algorithm to minimize obstacles encountered while traversing a grid. In this blog, we’ll break down the solution step-by-step in JavaScript.
Problem Description
Given a binary m x n
grid, the goal is to move from the top-left corner (0,0)
to the bottom-right corner (m-1, n-1)
with the minimum obstacles removed. Obstacles are represented by 1
s, while passable cells are 0
s.
Key Concepts
- Dijkstra’s Algorithm: This greedy algorithm finds the shortest path in a weighted graph. Here, “weights” correspond to the number of obstacles removed.
- Priority Queue: To prioritize cells based on the number of obstacles removed.
- Grid Traversal: Using directional vectors to explore neighbors.
JavaScript Solution
Step-by-Step Breakdown
- Initialization:
- Retrieve the grid’s dimensions (
m
andn
). - Define directional vectors for movement: up, down, left, right.
- Initialize a
result
matrix withInfinity
values, whereresult[i][j]
represents the minimum obstacles removed to reach(i, j)
. Start withresult[0][0] = 0
.
- Retrieve the grid’s dimensions (
- Priority Queue:
- Use a
MinPriorityQueue
to process grid cells by the number of obstacles removed. This ensures cells with fewer obstacles are explored first.
- Use a
- Grid Traversal:
- Use a loop to dequeue the top-priority cell.
- For each cell, explore its neighbors using the directional vectors.
- If a neighbor is within bounds, calculate the new number of obstacles removed (
additionalObstacle
). Update the result matrix and enqueue the neighbor if this path is better.
- Result:
- After the queue is empty, return the value at the bottom-right corner (
result[m-1][n-1]
).
- After the queue is empty, return the value at the bottom-right corner (
Complete Code
codevar minimumObstacles = function(grid) {
let m = grid.length;
let n = grid[0].length;
let directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
let result = Array.from({ length: m }, () => new Array(n).fill(Infinity));
result[0][0] = 0;
let priorityQueue = new MinPriorityQueue({ priority: x => x.weight });
priorityQueue.enqueue({ weight: 0, position: [0, 0] });
while (!priorityQueue.isEmpty()) {
let { element } = priorityQueue.dequeue();
let { weight: obstaclesRemoved, position } = element;
let [i, j] = position;
for (let direction of directions) {
let x = i + direction[0];
let y = j + direction[1];
if (x < 0 || x >= m || y < 0 || y >= n) {
continue;
}
let additionalObstacle = grid[x][y] === 1 ? 1 : 0;
if (obstaclesRemoved + additionalObstacle < result[x][y]) {
result[x][y] = obstaclesRemoved + additionalObstacle;
priorityQueue.enqueue({
weight: obstaclesRemoved + additionalObstacle,
position: [x, y]
});
}
}
}
return result[m - 1][n - 1];
};
Explanation with an Example
Input:
codegrid = [
[0, 1, 1],
[1, 1, 0],
[1, 0, 0]
];
Output:
code2
Walkthrough:
- Start at
(0,0)
with0
obstacles removed. - Move to adjacent cells, calculating the number of obstacles.
- Use the priority queue to always prioritize cells with fewer obstacles.
- Ultimately, reach
(2,2)
with2
obstacles removed.
Complexity Analysis
- Time Complexity:
- Each cell is processed at most once, leading to
O(m * n)
operations. - For each cell, the neighbors are checked in constant time.
- Each cell is processed at most once, leading to
- Space Complexity:
- The
result
matrix and priority queue requireO(m * n)
space.
- The
Key Takeaways
- Combining Dijkstra’s algorithm with a priority queue provides an efficient approach to solving this problem.
- Understanding graph algorithms and their applications to grid problems is crucial for competitive programming.