1. 程式人生 > >《程式設計師程式碼面試指南》 矩陣最長遞增路徑問題——java實現

《程式設計師程式碼面試指南》 矩陣最長遞增路徑問題——java實現

矩陣最長遞增路徑問題

題目描述:

給定一個整數矩陣matrix,每個位置你可以向左、右、下、上移動,找到其中最長的遞增路徑。 例如: matrix = [ [9,9,4], [6,6,8], [2,1,1] ] 返回4 最長路徑是[1, 2, 6, 9]. matrix = [ [3,4,5], [3,2,6], [2,2,1] ] 返回4 最長路徑是[ 2, 4,5, 6]

題目難度:

medium

題目思路:

本題可用三種方法: 暴力遞迴、記憶搜尋、動態規劃

思路一: 直接暴力遞迴求解。 對於每一個位置上的數,其實有四種移動路線,即向上、下、左、右。移動時,只要保證向其他位置可移動(不越界,並保證下一個位置大於當前位置值)即可,求出從當前位置出發的最長遞增路徑。 最終比較,求出所有位置的最長遞增路徑。

程式碼實現:

    public static int longest(int[][] matrix) {
    
    		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
			return 0;
		}
 
        int max = 0;
        for (int row = 0; row < matrix.length; row++) {
            for (int col = 0; col < matrix[0].length; col++) {
                max =
Math.max(max, process(matrix, row, col)); //獲取總的最長遞增路徑 } } return max; } private static int process(int[][] matrix, int row, int col) { //求當前位置最長的遞增路徑 int path = 1; // 原地不動的長度 if (row > 0 && matrix[row - 1][col] > matrix[row][col]) { //向上移動時
path = Math.max(path, process(matrix, row - 1, col) + 1); } if (col > 0 && matrix[row][col - 1] > matrix[row][col]) { //向左移動時 path = Math.max(path, process(matrix, row, col - 1) + 1); } if (row < matrix.length - 1 && matrix[row + 1][col] > matrix[row][col]) { //向下移動時 path = Math.max(path, process(matrix, row + 1, col) + 1); } if (col < matrix[0].length - 1 && matrix[row][col + 1] > matrix[row][col]) { //向右移動時 path = Math.max(path, process(matrix, row, col + 1) + 1); } return path; //返回當前位置的最長遞增路徑 }

思路二: 記憶搜尋方法 由於思路一的暴力遞迴求解過程中存在大量位置重複計算問題。而記憶搜尋是採用dp矩陣記錄每一個位置是否在之前通過遞迴求解過。若已經求解過,只需要把上次的值直接拿過來即可。因此該思路建立的dp類似快取棧的思想,若該值快取過,就不需要再計算了。

程式碼實現:

    public static int longestDP(int[][] matrix) {
    
    		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
			return 0;
		}
 
        int max = 0;
        int dp[][] = new int[matrix.length][matrix[0].length];   //快取矩陣
        
        for (int row = 0; row < matrix.length; row++) {
            for (int col = 0; col < matrix[0].length; col++) {
                max = Math.max(max, processDP(matrix, dp, row, col));  //獲取總的最長遞增路徑
            }
        }
        return max;
    }

    private static int processDP(int[][] matrix, int[][] dp, int row, int col) { //求當前位置最長的遞增路徑
        if (dp[row][col] == 0) {    //若該值沒有計算過,則計算當前最長遞增路徑
            dp[row][col] = 1;       // 原地不動的長度
            if (row > 0 && matrix[row - 1][col] > matrix[row][col]) {      //向上移動時
                dp[row][col] = Math.max(dp[row][col], processDP(matrix, dp, row - 1, col) + 1);
            }
            if (col > 0 && matrix[row][col - 1] > matrix[row][col]) {      //向左移動時
                dp[row][col] = Math.max(dp[row][col], processDP(matrix, dp, row, col - 1) + 1);
            }
            if (row < matrix.length - 1 && matrix[row + 1][col] > matrix[row][col]) { //向下移動時
                dp[row][col] = Math.max(dp[row][col], processDP(matrix, dp, row + 1, col) + 1);
            }
            if (col < matrix[0].length - 1 && matrix[row][col + 1] > matrix[row][col]) {   //向右移動時
                dp[row][col] = Math.max(dp[row][col], processDP(matrix, dp, row, col + 1) + 1);
            }
        }
        return dp[row][col];   //返回當前位置的最長遞增路徑
    }

思路三:動態規劃 採用動態規劃的思想,使得時間複雜度降到o(m*n)

程式碼實現:

    public static int longestIncreasingPath(int[][] matrix) {

        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }

        int max = 0;
        int dp[][] = new int[matrix.length][matrix[0].length];   //動歸矩陣

        for (int row = 0; row < matrix.length; row++) {
            for (int col = 0; col < matrix[0].length; col++) {
                //要求當前位置的最長遞增路徑,需求當前位置往上下左右分別的最大遞增路徑。
                max = Math.max(max, maxIncrease(matrix, dp, row + 1, col, matrix[row][col]) + 1);   //下
                max = Math.max(max, maxIncrease(matrix, dp, row - 1, col, matrix[row][col]) + 1);   //上
                max = Math.max(max, maxIncrease(matrix, dp, row, col + 1, matrix[row][col]) + 1);    //右
                max = Math.max(max, maxIncrease(matrix, dp, row, col - 1, matrix[row][col]) + 1);    //左
            }
        }
        return max;
    }

    private static int maxIncrease(int[][] matrix, int[][] dp, int row, int col, int pre) { //往當前方向走的最長遞增路徑
        if (row < 0 || row >= matrix.length || col < 0 || col >= matrix[0].length || matrix[row][col] >= pre) {
            return 0;
        }

        if (dp[row][col] == 0) {          //當前位置沒有計算過
            dp[row][col] = maxIncrease(matrix, dp, row + 1, col, matrix[row][col]) + 1;
            dp[row][col] = Math.max(dp[row][col], maxIncrease(matrix, dp, row, col + 1, matrix[row][col]) + 1);
            dp[row][col] = Math.max(dp[row][col], maxIncrease(matrix, dp, row - 1, col, matrix[row][col]) + 1);
            dp[row][col] = Math.max(dp[row][col], maxIncrease(matrix, dp, row, col - 1, matrix[row][col]) + 1);
        }
        return dp[row][col];
    }