0

I been grinding leetcode using JavaScript and I was trying to solve this question https://leetcode.com/problems/shortest-path-in-binary-matrix/

This question was asking to return the distance or the length of the shortest path, and I solved it. Here is my answer

var shortestPathBinaryMatrix = function(grid) {
    if(grid[0][0] != 0) return -1
    const queue = [[[0,0], 1]]
    const dest = [grid.length - 1, grid[0].length - 1]
    const visited = new Set()
    const getNextSteps = ([x,y]) => {
        const dirs = [[1, 0], [-1, 0] , [0,1], [0,-1], [1,1], [-1,1], [-1,-1], [1,-1]]
        const nextSteps = []
        for(const [nx, ny] of dirs) {
            if(grid[x + nx]?.[y + ny] == 0) nextSteps.push([x + nx, y + ny])
        }
        
        return nextSteps
    }
    
    for(const [curr, distance] of queue) {
        if(visited.has(curr.toString())) continue
        if(curr[0] === dest[0] && curr[1] === dest[1] && grid[dest[0]][dest[1]] == 0) return distance
        visited.add(curr.toString())
        getNextSteps(curr).forEach(adj => queue.push([adj, distance + 1]))
    }
    
    return -1
    
};

However I wonder if I can also get the actual paths it takes to reach the end of the matrix, so instead of returning a number as the length of the path, I want to return the actual paths which is an array of coordinates it visited on the shorted path.

For example, if the input grid is [[0,0,0],[1,1,0],[1,1,0]], it should return [ [ 0, 0 ], [ 0, 1 ], [ 1, 2 ], [ 2, 2 ] ] 

But it is harder to do than it seems. I tried a few ways but I couldn't seem to solve it. Can anyone give it a try?

Joji
  • 2,372
  • 1
  • 12
  • 31

1 Answers1

1

The main idea is to make visited a Map instead of a Set, and to register as value the coordinates of the previous node on the path to that visited node.

For that to work I find it easier to make the visited mark one step earlier than you did: make the mark when you put the cell on the queue, not when you pull it from the queue.

Once you arrive at the destination you can use the Map as a linked list, and walk back along the path towards the source node. That way you can reconstruct the path. Then just remains to reverse it.

Here is your code with the modifications marked with a comment:

var shortestPathBinaryMatrix = function(grid) {
    if(grid[0][0] != 0) return []; // modify return type
    const queue = [[[0,0], 1]];
    const dest = [grid.length - 1, grid[0].length - 1];
    const visited = new Map();
    visited.set([0,0].toString(), null); // Mark source as visited

    const getNextSteps = ([x,y]) => {
        const dirs = [[1, 0], [-1, 0] , [0,1], [0,-1], [1,1], [-1,1], [-1,-1], [1,-1]];
        const nextSteps = [];
        for(const [nx, ny] of dirs) {
            if(grid[x + nx]?.[y + ny] == 0) nextSteps.push([x + nx, y + ny]);
        }
        return nextSteps;
    }
    
    for (let [curr, distance] of queue) {
        // Move the visited check to the loop
        if (curr[0] === dest[0] && curr[1] === dest[1] && grid[dest[0]][dest[1]] == 0) {
            // Derive the path from the linked list we now have in the visited structure:
            let path = [];
            while (curr) {
                path.push(curr);
                curr = visited.get(curr.toString());
            }
            return path.reverse(); // Need to reverse to get from source to destination
        }
        for (let adj of getNextSteps(curr)) {
            // Visited-check moved here:
            if (visited.has(adj.toString())) continue; 
            // Mark with the coordinates of the previous node on the path:
            visited.set(adj.toString(), curr);
            queue.push([adj, distance + 1]);
        }
    }
    
    return []; // must modify this as well
};

// demo
let grid = [[0,0,0],[1,1,0],[1,1,0]];
let result = shortestPathBinaryMatrix(grid);
console.log(result);

Unrelated: it is good to make it a habit to terminate your statements with a semi-colon. Making your code dependent on the automatic semi-colon insertion algorithm is possible of course, but you would not be the first to fall for one of the obscure traps it has.

trincot
  • 211,288
  • 25
  • 175
  • 211