Search code examples
javaalgorithmgraphdepth-first-searchbreadth-first-search

Distance of nearest cell having 1


Given a binary matrix of size N x M. The task is to find the distance of nearest 1 in the matrix for each cell. The distance is calculated as |i1 – i2| + |j1 – j2|, where i1, j1 are the row number and column number of the current cell and i2, j2 are the row number and column number of the nearest cell having value 1.

Input: The first line of input is an integer T denoting the number of test cases. Then T test cases follow. Each test case consists of 2 lines . The first line of each test case contains two integers M and N denoting the number of rows and columns of matrix . Then in the next line are N*M space separated values of the matrix (mat) .

Here is my code:

class GFG {
public static void markNearest(int R, int C, int[][] M,int[][] out,Queue<Vertex> q, boolean[][] visited){
    int[] x_pos ={1,-1,0,0};
    int[] y_pos ={0,0,-1,1};
    while(!q.isEmpty()){
        Vertex v = q.poll();
        int x = v.i;
        int y = v.j;
        int d = v.dist;
        
        visited[x][y] = true;
        for(int k=0;k<=3;k++){
            if(isSafe(x+x_pos[k],y+y_pos[k],R,C,visited)){
                if(out[x+x_pos[k]][y+y_pos[k]] == -1){
                    out[x+x_pos[k]][y+y_pos[k]] = d+1;
                    q.add(new Vertex(x+x_pos[k],y+y_pos[k],d+1));
                }
            }
        }
    }
    
    
}

private static boolean isSafe(int i, int j, int r, int c, boolean[][] visited) {
    return (i >= 0 && i < r && j >= 0 && j < c && !visited[i][j]);
}

private static void printMatrixInline(int[][] M) {
    for(int i=0;i<M.length;i++) {
        for(int j=0;j<M[0].length;j++) {
            System.out.print(M[i][j]+" ");
        }
    }
}
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int T = sc.nextInt();
    for (int t = 0; t < T; t++) {
        int R = sc.nextInt();
        int C = sc.nextInt();
        int[][] M = new int[R][C];
        int[][] out = new int[R][C];
        Queue<Vertex> q = new LinkedList<>();
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                M[i][j] = sc.nextInt();
                if(M[i][j] ==1){
                    q.add(new Vertex(i,j,0));
                    out[i][j] = 0;
                }
                else{
                    out[i][j] = -1;
                }
            }
        }
        boolean[][] visited = new boolean[R][C];
        markNearest(R, C,M,  out, q, visited);
        printMatrixInline(out);
        System.out.println();
    }

}

}

My program took more time than expected.

Please suggest what is wrong with the code.


Solution

  • Basically, during you recursive calls, if you encounter a cell with no unvisited neighbor (which happens) you will return Integer.MAX_VALUE. From there things go bad.

    More importantly, your distance calculation is wrong because your recursive calls are depth first instead of breadth first.

    Here with some drawings. You are considering the neighbors in this order (because of x_pos and y_pos)

     ----> y
    | 678
    | 4.5
    | 123
    v
    x
    

    Let's see what happens when you start on the x cell (dots for cells with a one:

    0  0  0  .  .  0  .  0  0  0  .  0  0
    0  0  .  .  .  0  0  .  0  0  .  .  .
    0  0  .  0  0  .  0  .  .  .  .  0  .
    .  0  0  .  0  0  0  0  0  .  0  0  0
    .  0  0  0  0  x  0  .  0  .  .  .  0
    

    Here are the recursive depth of each call to findNearest:

    11 12 13 14 17 16 17 16 19 20 21 .. .. 
     9 10 11 14 16 14 15 16 17 18 19 .. .. 
     8  7 11  7 15 14 13 15 15 15 19 .. .. 
     5  5  6  7  8  9 11 12 14 15 .. .. .. 
     5  4  3  2  1  0 10 11 13 14 .. .. .. 
    

    and the corresponding (>0) return values:

     3  2  1 .. ..  1 ..  1  2  1 .. .. .. 
     2  1 .. .. ..  1  1 ..  1  1 .. .. .. 
     1  1 ..  1  1 ..  1 .. .. .. .. .. .. 
    ..  1  1 ..  1  1  2  1  1 .. .. .. .. 
    ..  1  2  1  2  3  1 ..  1 .. .. .. ..
    

    But keep only the one for the x cell, here 3. But it's false! It's just because you went left first. Here all neighbors numbered more than 1 are visited from deeper recursion, and marked as not "safe" from the point of view of your outer call. The result here should be 2.

    You can also see here another problem in your code, you recompute for each cell a bunch of (false) distances. For a bigger matrix, you'll do O((n.m)**2) work instead of the O(n.m) necessary here.