Search code examples
javaalgorithmdata-structuresdepth-first-search

Use a depth first to traverse a matrix


Problem

You are given a two-dimensional array (matrix) of potentially unequal height and width containing only 0s and 1s. Each 0 represents land, and each 1 represents part of a river. A river consists of any number of 1s that are either horizontally or vertically adjacent (but not diagonally adjacent). The number of adjacent 1s forming a river determine its size. Write a function that returns an array of the sizes of all rivers represented in the input matrix. Note that these sizes do not need to be in any particular order.

Input 
[
[1,0,0,1,0],
[1,0,1,0,0],
[0,0,1,0,1],
[1,0,1,0,1],
[1,0,1,1,0],
]

Output [1,2,2,2,5]

My Approach

After evaluating the problem i felt like this should be done using a graph traversal like algorithm maybe depth first search. So that is exactly what i do .

I traverse the matrix from top left and see if the value is visited and if it is not then and if the value is 1 then i traverse all it's nodes and keep a counter to keep size of the river. In the end i update an array list with the total river size.

For some reason my result is not correct and i am not sure what i did wrong. I hand traced my code too but can't figure out the issue.

My Code

import java.util.ArrayList;

class Program {
  public static ArrayList<Integer> riverSizes(int[][] matrix) {
    ArrayList<Integer> result = new ArrayList<Integer>();
        boolean [][] visitStatus = new boolean [matrix.length][matrix[0].length];

        for(int row = 0; row<matrix.length; row++){
            for(int col = 0; col<matrix.length; col++){
                int count = 0;
                count = traverseMatrix(row,col,matrix,visitStatus,count);
                result.add(count);
            }
        }
        return result;
  }

    public static int traverseMatrix(int row, int col, int [][] matrix, boolean [][] visitStatus, int count){
        if(visitStatus[row][col] == true){
            return count;
        }else if(matrix[row][col] == 0){
            visitStatus[row][col] = true;
            return count;
        }else{
            count++;
            visitStatus[row][col] = true;
            if(isValid(row,col-1,matrix)){
                return traverseMatrix(row,col-1,matrix,visitStatus,count);
            }
            if(isValid(row,col+1,matrix)){
                return traverseMatrix(row,col+1,matrix,visitStatus,count);
            }
            if(isValid(row-1,col,matrix)){
                return traverseMatrix(row-1,col,matrix,visitStatus,count);
            }
            if(isValid(row+1,col,matrix)){
                return traverseMatrix(row+1,col,matrix,visitStatus,count);
            }
        }
        return count;
    }

    public static boolean isValid(int row, int col,int[][] matrix){
        return (row >= 0 && row < matrix.length) && (col >= 0 && col < matrix[0].length);
    }
}

Solution

  • Convert count to a local variable and accumulate it:

    static int traverseMatrix(int row, int col, int[][] matrix, boolean[][] visitStatus) {
        if (visitStatus[row][col] || matrix[row][col] == 0) {
            return 0;
        }
        visitStatus[row][col] = true;
        int count = 1;
        if (isValid(row, col - 1, matrix)) {
            count += traverseMatrix(row, col - 1, matrix, visitStatus);
        }
        ...
        return count;
    }