javarecursionmatrixpath-findinglongest-path

How to return the longest path in matrix using recursion in JAVA


I am trying to solve this problem with recursion.
The problem is: for a two dimensional array of positive integers how can I return the longest path (steps), so that the value in each cell of the longest path is from descending series of integers and the difference between each cell and cell is a given number (num).
Assumes that n is a value of the cell so (n - num) is a positive number (not zero).
I can't use any loops (for,while,...etc)

the Method:

public static int longestPath(int matrix[][],int number){...
return(__overloading__);
}

For example:

int number=1;
int [][]matrix ;
       matrix = new int[][]{{8, 15, 20, 33, 35},
                           {60, 59, 58, 32, 31},
                           {59, 17, 57, 56, 55},
                           {55, 15, 13, 58, 16}};

     System.out.print(" longestPath= "+ longestPath(matrix, num));
   }

if we search for the longest path with the difference number = 1

1-in the cell matrix[0][3] the path long is 3 and the value in this path is 33 -> 32 -> 31 ends in matrix[1][4]

2-in the cell matrix[1][0] the path long is for 6 and the value in the path 60 -> 59 -> 58 -> 57 -> 56 -> 55 ends in matrix[2][4]

3-in the cell matrix[1][0] the path long is 2 and the value in this path is 60 -> 59 ends in matrix[2][0]

so the method must return the longest path witch its 6

if we search for the longest path with the difference number = 2

1-in the cell matrix[2][1] the path long is 3 and the value in this path is 17 -> 15 -> 13 ends in matrix[3][2]

the method must return the longest path witch its 3.

My non-working code:

public class CC {

    public static int longestPath (int arr[][] , int  num){
        return longestPath(arr,arr.length-1,arr[0].length-1,num,0);
    }

    public static int longestPath (int arr[][],int rows,int cols,int num,int max){
        System.out.println("==> longestPath() arr value=" + arr[rows][cols] + " rows:"+rows + " cols:"+cols + " max:"+max);
        if (cols ==0 && rows != 0  ){  
            cols = arr[0].length-1;
            rows--;
        }
        if (rows ==0  && cols==0 ){
            System.out.println("finish");
            return 0;
        }

        int steps = searchPath(arr,rows,cols,num,max);
        if (steps > max) max=steps;
        longestPath(arr,rows,cols-1,num,max);
        return max ;
    }

    public static int searchPath(int arr[][],int rows,int cols,int num ,int counter){ 
        System.out.println("searchPath() arr value=" + arr[rows][cols] + " rows:"+rows + " cols:"+cols);
        int left=1,right=1,up=1,down=1;

        if ((cols != 0) && arr[rows][cols] - num == arr[rows-1][cols]  ){ // checking up cell
            counter++;
            up = searchPath(arr,rows-1,cols,num,counter);

        }
        if ((rows != arr.length-1)   &&   arr[rows][cols] - num == arr[rows+1][cols] ){ // checking down cell
            counter++;
            down = searchPath(arr,rows+1,cols,num,counter);
            // return counter;
        }
        if ((cols != 0)  &&  arr[rows][cols] - num == arr[rows][cols-1]){ // checking left cell
            counter++;
            left = searchPath(arr,rows,cols-1,num,counter);
            //return counter;
        } 
        if ((cols != arr[0].length-1)   &&   arr[rows][cols] - num == arr[rows][cols+1]  ){ //checking right cell
            counter++;
            right = searchPath(arr,rows,cols+1,num ,counter);
            //return counter;
        } 

        if ((left > right) && (left > up)    && (left > down)) // if left cell is bigger than all other direction return left
            return left;
        if ((right > left) && (right > up)   && (right > down))
            return right;
        if ((down > up)    && (down > right) &&( down > left))
            return down;
        if ((up> down) && (up > right) && (up>left))
            return up;

        return 0;
    }

}

While writing the code, I ran into a lot of running problems

what i'm doing wrong? thanks in advance


Solution

  • In the posted solution (as well as in the question) you iterate over entire two-dimensional array, starting at the top-left (0,0), and want to check neighbors for each element.
    To check all neighbors, it is enough to check right and down neighbors to cover all1:

    enter image description here

    1: If you are interested in descending paths going up or left, you need to check 4 directions. This is because your graph is directed. For example, a path which may not be valid going left to right, may be valid going right to left.

    By doing so, you simplify the code, and reduce duplicate testing of neighbors.
    Another technique which makes code easier to read, debug and maintain, is breaking it into small well defined simple methods, for example:

    private static boolean isValidAddress(int row, int col, int maxRow, int maxCol) {
        if(row < 0 || col < 0) return false;
        if(row >= maxRow || col >= maxCol) return false;
        return true;
    }
    

    Try the following solution:

    public class Main {
    
        //moving in two directions, right and down, is sufficient
        //to cover a whole matrix without visiting the same address twice
    
        public static void main(String[] args) {
            int delta= 1;
            int [][]matrix =  new int[][]{
                                         {8, 15, 20, 33, 35},
                                         {60, 59, 58, 32, 31},
                                         {59, 17, 57, 56, 55},
                                         {55, 15, 13, 58, 16}};
            System.out.print(" longest Path= "+ longestPath(matrix, delta));
        }
    
         public static int longestPath (int arr[][] , int delta){
                return longestPath(arr, 0, 0, delta , 0);
         }
    
         //check all matrix elements, keep longest path found
         public static int longestPath (int arr[][],int row,int col, int num, int max){
    
            int steps = searchPath(arr,row,col,num, 1); //Initial path length is always 1
            if (steps > max) {  max=steps;  }
    
            if (row == arr.length-1 && col == arr[row].length -1 )  return max;
            col ++;
            if(col == arr[row].length){//end of row exceeded
                row++;    //new row
                col = 0;  //first column
            }
    
            return longestPath(arr,row,col,num,max);
        }
    
        public static int searchPath(int arr[][],int row,int col,int num ,int pathLength){
    
            int[][] neighbors = getNeighbors(arr, row, col, num);
            int rightPath = 0 , downPath = 0;
            //right neighbor
            if(neighbors[0] != null){
                rightPath = searchPath(arr, neighbors[0][0], neighbors[0][1], num, pathLength+1);
            }
    
            //down neighbor
            if(neighbors[1] != null){
                downPath = searchPath(arr, neighbors[1][0], neighbors[1][1], num, pathLength+1);
            }
    
            int returnPath = Math.max(rightPath, downPath); //max return value 
            return Math.max(pathLength, returnPath) ; //max of path length and returned value 
        }
    
        //return neighbors with value smaller by delta
        //returned array[0] represents right neighbor row, col  or null
        //returned array[1] represents down  neighbor row, col  or null
        private static int[][] getNeighbors(int[][] arr, int row, int col, int delta) {
    
            //moving in two directions, right and down, is sufficient
            //to cover a whole matrix without visiting the same address twice
    
            int[][] neighbors = {null, null};
            //right neighbor
            int newCol = col +1;
            if(isValidAddress(row, newCol, arr.length, arr[0].length)){
                if(arr[row][col] - arr[row][newCol] == delta){
                    neighbors[0] = new int[]{row, newCol};
                }
            }
    
            //down neighbor
            int newRow = row + 1 ;
            if(isValidAddress(newRow, col, arr.length, arr[0].length)){
                if(arr[row][col] - arr[newRow][col] == delta){
                    neighbors[1] = new int[]{newRow, col};
                }
            }
    
            return neighbors;
        }
    
        private static boolean isValidAddress(int row, int col, int maxRow, int maxCol) {
            if(row < 0 || col < 0) return false;
            if(row >= maxRow || col >= maxCol) return false;
            return true;
        }
    }