package com.interview.algorithms.array; import com.interview.utils.ConsoleReader; /** * Given an m*n grid, how many paths are there from the left bottom corner to * the up right corner. * * Here gives three solution: * 1. inverseCalculatePath: inverse calculate the path using the following formula * when m > 0 and n > 0: f(m, n) = f(m - 1, n) + f(m, n - 1) * when m = 0 and n > 0: f(m, n) = f(m, n - 1) * when m > 0 and n = 0: f(m, n) = f(m - 1, n) * when m = 0 and n = 0: f(m, n) = 1 * since we haven't store the path in the mid-step, it will calculate the same f(m,n) in different inverse process. * 2. inverseCalculatePathOptimized: use a long[][] to store the path num to prevent calculate them more then one time. * it will cost a long[m+1][n+1] array. * but it is much faster then the solution 1 when m and n are larger then 10. * 3. loopCalculatePath: since we have already use a long[][] array to store the path num, we can use loop instead of inverse to save memory. * f(0, 0) = 1; * f(0, 0..n) = 1; * f(0..n, 0) = 1; * f(m, n) = f(m - 1, n) + f(m, n - 1) * return f(m, n) * * @author zhaochenting (zhaochenting@gmail.com) * */ public class C4_10_PathCounter { /** * @param args */ public static void main(String[] args) { System.out.println("The Path Counter Implementation"); System.out.println("========================================================================"); ConsoleReader reader = new ConsoleReader(); System.out.print("Please input two number as the size of the grid (MAX is 33*33): "); int[] array = null; try{ array = reader.readIntItems(); }catch (RuntimeException e){ System.out.println("INPUT ERROR! Please input NUMBER for the size of the grid as M N"); return; } if(array == null || array.length < 2){ System.out.println("INPUT ERROR! Please input TWO number as the size of the grid as M N"); return; } Integer m = array[0]; Integer n = array[1]; if(m > 33 || n > 33){ System.out.println("INPUT ERROR! MAX Number of the size is 33 * 33"); return; } C4_10_PathCounter counter = new C4_10_PathCounter(); long path = counter.inverseCalculatePathOptimized(m, n); System.out.println("The path from the left bottom corner to the up right corner in a " + m + "*" + n + " grid is: " + path); } /** * inverse calculate the path using the following formula * when m > 0 and n > 0: f(m, n) = f(m - 1, n) + f(m, n - 1) * when m = 0 and n > 0: f(m, n) = f(m, n - 1) * when m > 0 and n = 0: f(m, n) = f(m - 1, n) * when m = 0 and n = 0: f(m, n) = 1 * @param m: the length of the grid * @param n: the weight of the grid * @return the path from the left bottom corner to the up right corner in grid m*n */ public long inverseCalculatePath(int m, int n) { if (m > 0 && n > 0) { return inverseCalculatePath(m - 1, n) + inverseCalculatePath(m, n - 1); } else if (m == 0 & n > 0) { return inverseCalculatePath(m, n - 1); } else if (n == 0 & m > 0) { return inverseCalculatePath(m - 1, n); } return 1; } /** * Optimize: store the calculate path into an array to prevent calculate the path has been calculated before * @param m: the length of the grid * @param n: the weight of the grid * @return the path from the left bottom corner to the up right corner in grid m*n */ public long inverseCalculatePathOptimized(int m, int n) { long pathArray[][] = new long[m + 1][n + 1]; for(int i = 0; i <= m; i++){ for(int j = 0; j <= n; j++){ pathArray[i][j] = 0; } } return inverseCalculatePathOptimized(m, n, pathArray); } /** * inverse calculate the path using the following formula * when m > 0 and n > 0: f(m, n) = f(m - 1, n) + f(m, n - 1) * when m = 0 and n > 0: f(m, n) = f(m, n - 1) * when m > 0 and n = 0: f(m, n) = f(m - 1, n) * when m = 0 and n = 0: f(m, n) = 1 * with a optimize: store the calculate path into an array to prevent calculate the path has been calculated before * @param m: the length of the grid * @param n: the weight of the grid * @param pathArray: the array to store the paths have been calculated * @return the path from the left bottom corner to the up right corner in grid m*n */ public long inverseCalculatePathOptimized(int m, int n, long[][] pathArray) { //search in the path array firstly, in order to prevent calculate the path has been calculated before if(pathArray[m][n] != 0){ return pathArray[m][n]; } long path = 1; if (m > 0 && n > 0) { path = inverseCalculatePathOptimized(m - 1, n) + inverseCalculatePathOptimized(m, n - 1); } else if (m == 0 & n > 0) { path = inverseCalculatePathOptimized(m, n - 1); } else if (n == 0 & m > 0) { path = inverseCalculatePathOptimized(m - 1, n); } pathArray[m][n] = path; return path; } /** * with a optimize: store the calculate path into an array to prevent calculate the path has been calculated before * using loop instead of inverse to calculate the path * f(0, 0) = 1; * f(0, 0..n) = 1; * f(0..n, 0) = 1; * f(m, n) = f(m - 1, n) + f(m, n - 1) * @param m: the length of the grid * @param n: the weight of the grid * @return the path from the left bottom corner to the up right corner in grid m*n */ public long loopCalculatePath(int m, int n) { //search in the path array firstly, in order to prevent calculate the path has been calculated before long pathArray[][] = new long[m + 1][n + 1]; pathArray[0][0] = 1; for(int i = 1; i <= m; i ++){ pathArray[i][0] = 1; } for(int j = 1; j <= n; j ++){ pathArray[0][j] = 1; } for(int i = 1; i <= m; i ++){ for(int j = 1; j <= n; j ++){ pathArray[i][j] = pathArray[i - 1][j] + pathArray[i][j - 1]; if(pathArray[i][j] < 0){ System.out.println("m: " + i + " n: " + j + " path: " + pathArray[i][j]); return -1; } } } return pathArray[m][n]; } }