Mlog4: LeetCode --矩陣中的最長遞增路徑

2019-4-22

文章目錄:

  1. 題目要求
  2. 解題思路
  3. 具體實(shí)現(xiàn)
  4. 改進(jìn)之路
  5. 總結(jié)

1. 題目要求

給定一個(gè)整數(shù)矩陣,找出最長遞增路徑的長度。

對(duì)于每個(gè)單元格,你可以往上,下,左,右四個(gè)方向移動(dòng)。 你不能在對(duì)角線方向上移動(dòng)或移動(dòng)到邊界外(即不允許環(huán)繞)。

示例 1:
輸入: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
輸出: 4
解釋: 最長遞增路徑為 [1, 2, 6, 9]。

示例 2:
輸入: nums =
[
[3,4,5],
[3,2,6],
[2,2,1]
]
輸出: 4
解釋: 最長遞增路徑是 [3, 4, 5, 6]。注意不允許在對(duì)角線方向上移動(dòng)。
--題目來源于 leetcode

2. 解題思路

2.1 二維數(shù)組存儲(chǔ)數(shù)據(jù) int[][] matrix,int[][] dpn 記錄路徑.
2.2 參考動(dòng)態(tài)規(guī)劃之記憶化搜索 滑雪問題:

image

上圖顯示為R*C的雪場,R是行數(shù),C是列數(shù)。圓圈內(nèi)的數(shù)字表示的是雪場的海拔高度h,根據(jù)常識(shí)我們知道,滑雪只有從上往下滑行才可能滑的動(dòng),現(xiàn)在我們想要求出能夠滑行的最長距離,上面的例子我們可以很直接判斷出25-24-......-1這個(gè)順時(shí)針方向螺旋的滑雪方式可以滑的最遠(yuǎn)。

那么這個(gè)問題如何用編程來實(shí)現(xiàn)呢?我們發(fā)現(xiàn)這是一個(gè)典型的遞推,DP(i, j)表示從坐標(biāo)(i,j)出發(fā)所能滑行的最大長度,且有:DP(i, j)=optimal{DP(i±1, j±1)}+1.

2.3 DP記憶化搜索

dfs(problem a){
    if(a has been solved) 
        then: consult the record.
    else//get the optimal solution of problem a.
        divide the problem a into several sub-problems(a1,a2,...,ak)
        get the solution of problem a by dfs(a1),dfs(a2),...,dfs(ak).
    finally write the optimal solution into record.
}

3. 具體實(shí)現(xiàn)

3.1 示例代碼

package cxy.com;

public class LongestIncrementalPath {
    
    static int row;//行
    static int colcumn;//列
    
    public static void main(String[] args) {
    /**
     * [
  [9,9,4],
  [6,6,8],
  [2,1,1]
        ]
     */
     int[][] m = {{9,9,4},{6,6,8},{2,1,1}};//示例
     int length = LongestIncrementPath(m);
     System.out.println("最長遞增路徑的長度:"+length);   
        
    }
  
    public static int LongestIncrementPath(int[][] matrix) {
        if(matrix==null||matrix.length==0)return 0;
        int max=1;
        row=matrix.length;
        colcumn=matrix[0].length;  
        int dpn[][]=new int[row][colcumn];//記錄該點(diǎn)出發(fā)的最長路徑,走過就記錄長度,沒有就是初值==0;
        for(int i=0;i<row;i++){//初值:沒走過就是==0;
            for(int j=0;j<colcumn;j++){
            dpn[i][j]=0;
            }
        }
        for(int i=0;i<row;i++){//以每個(gè)點(diǎn)為起點(diǎn)掃描
            for(int j=0;j<colcumn;j++){
               int t= longestPath(i,j,matrix,dpn);//方法:以該點(diǎn)出發(fā)的最大長度
                if(t>max)max=t;//比較:max記為最大
            }
        }
        return max;
    }
    
    static int longestPath(int x,int y,int [][]mat,int dpn[][]){
        if(x<0||y<0||x>=row||y>=colcumn)//越界判斷;
        return 0;
        if(dpn[x][y]!=0)return dpn[x][y];//走過的話,直接取值
        int max=0;
      //----------向左走
        if(y-1>=0 && mat[x][y]<mat[x][y-1]){
            int temp;
          //走過的話,直接取值
            if(dpn[x][y-1]!=0)temp=dpn[x][y-1];
                else temp=longestPath(x,y-1,mat,dpn);//遞歸
            max=max>temp?max:temp;//記錄最大
        }
      //----------向右走
        if(y+1<colcumn && mat[x][y]<mat[x][y+1]){
            int temp;
            if(dpn[x][y+1]!=0)temp=dpn[x][y+1];
                else temp=longestPath(x,y+1,mat,dpn);
            max=max>temp?max:temp;
        }
      //------------向下走
        if(x-1>=0 && mat[x][y]<mat[x-1][y]){
            int temp;
            if(dpn[x-1][y]!=0)temp=dpn[x-1][y];
                else temp=longestPath(x-1,y,mat,dpn);
            max=max>temp?max:temp;
        }
      //------------向上走
        if(x+1<row && mat[x][y]<mat[x+1][y]){
            int temp;
            if(dpn[x+1][y]!=0)temp=dpn[x+1][y];
            else temp=longestPath(x+1,y,mat,dpn);
            max=max>temp?max:temp;
        }
      //記為走過了,并存下 以此點(diǎn)出發(fā)的路徑長度
        if(dpn[x][y]==0)dpn[x][y]=max+1;
        return dpn[x][y];
        
    }

}

3.2 執(zhí)行結(jié)果與分析:

最長遞增路徑的長度:4


2018-5-29

4. 改進(jìn)之路

通過 leetcode 可以看出,執(zhí)行時(shí)間相對(duì)較短,但是內(nèi)存消耗大。參考評(píng)論區(qū)的其他大佬們的思路和答案,可以有另外一種更優(yōu)的解法。
---leetcode 玩家 gyx2110的答案

package cxy.com;

public class LongestIncrementalPath {
    
    static int row;//行
    static int colcumn;//列
    
    public static void main(String[] args) {
    /**
     * [
  [9,9,4],
  [6,6,8],
  [2,1,1]
        ]
     */
     int[][] m = {{9,9,4},{6,6,8},{2,1,1}};//示例
     int length =longestIncreasingPath(m);
     System.out.println("最長遞增路徑的長度【1】:"+length);    

    }
    
    public static int longestIncreasingPath(int[][] matrix) {
        if (matrix.length == 0)
            return 0;
        int m = matrix.length, n = matrix[0].length;
        int[][] dirs = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
        int[][] map = new int[m][n];
        int res = 1;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res = Math.max(res, dfs(matrix, i, j, map, dirs));
            }
        }
        return res;
    }
    
    // dfs求以點(diǎn)(i,j)結(jié)尾的最長遞增路徑
    public static int dfs(int[][] matrix, int i, int j, int[][] map, int[][] dirs) {
        if (map[i][j] != 0)
            return map[i][j];
        int res = 1;
        for (int[] dir : dirs) {
            int x = i + dir[0], y = j + dir[1];

            if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length || matrix[x][y] >= matrix[i][j])
                continue;
            // 當(dāng)周圍的點(diǎn)小于當(dāng)前點(diǎn)才遞歸
            res = Math.max(res, 1 + dfs(matrix, x, y, map, dirs));
        }
        map[i][j] = res;
        return res;
    }
  
}

執(zhí)行結(jié)果與分析:

最長遞增路徑的長度【1】:4


2019-5-29

5. 總結(jié)

記憶化搜索 = 搜索的形式 + 動(dòng)態(tài)規(guī)劃的思想。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容