描述
给定一个n行m列矩阵 matrix,矩阵内所有数均为非负整数。
求一条路径,该路径上所有数是递增的。
这个路径必须满足以下条件:- 对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外。
- 你不能走重复的单元格。即每个格子最多只能走一次。
数据范围:
方法一
思路
深度优先搜索;
题目要求找出矩阵中最长递增路径,然而却没有指定路径的开始节点,所以需要遍历所有的节点,以每一个节点为头结点找出最长的递增路径;
假设指定头结点为(row,col),那么从这个节点开始的下一步有以下四中走法:
当然需要判断是否越过边界了以及下一步的值是大于点(row,col)的值的;通过上述的走法可以得出如下递推公式:
代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 递增路径的最大长度 * @param matrix int整型二维数组 描述矩阵的每个数 * @return int整型 */ public int solve (int[][] matrix) { int max = 0; if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return max; } // 以所有的节点为路径的开始节点 for (int i = 0;i < matrix.length;++i){ for (int j = 0;j < matrix[0].length;++j){ // 计算从(i,j)开始的最长递增路径 int temp = searchMaxPath(matrix,i,j,-1); max = Math.max(temp,max); } } return max; } // 计算以点(row,col)为路径头结点的最长递增路径 private int searchMaxPath(int[][] matrix,int row,int col,int pre){ if (row < 0 || col < 0 || row >= matrix.length || col >= matrix.length){ return 0; } if (matrix[row][col] <= pre){ return 0; } int max = 0; int temp = 0; // 点(row,col)往上走的最长路径 temp = searchMaxPath(matrix,row-1,col,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往下走的最长路径 temp = searchMaxPath(matrix,row+1,col,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往左走的最长路径 temp = searchMaxPath(matrix,row,col-1,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往右走的最长路径 temp = searchMaxPath(matrix,row,col+1,matrix[row][col]); max = Math.max(temp,max); return max+1; } }
时间复杂度:,双重循环为mn,而dfs最坏情况为4mn;
空间复杂度:,递归调用的深度不会超过mn。
方法二
思路
- 深度优先,记忆表;
- 方法一的时间复杂度过大,在处理大量数据时会比较吃力,所以需要考虑降低其时间复杂度;
- 我们知道在方法一中计算以点(row,col)为头结点时,其下一步最多会有四种走法(rownext,colnext),且需要求出以(rownext,colnext)为头结点的最长递增路径,可以发现这之间是存在很多的重复计算的,毕竟一个节点是可能被多条路径所经过的;
- 所以我们可以考虑使用一个矩阵(记忆表)来记录以当前节点为头结点的最长递增路径,这样子当某一节点的路径经过已记录的节点时,就可以直接从矩阵中拿出已经记录的数据,而无需再次计算。
- 代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 递增路径的最大长度 * @param matrix int整型二维数组 描述矩阵的每个数 * @return int整型 */ // 记忆表 private int[][] paths; public int solve (int[][] matrix) { int max = 0; if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return max; } // 初始化 paths = new int[matrix.length][matrix[0].length]; // 以所有的节点为路径的开始节点 for (int i = 0;i < matrix.length;++i){ for (int j = 0;j < matrix[0].length;++j){ // 计算从(i,j)开始的最长递增路径 int temp = searchMaxPath(matrix,i,j,-1); max = Math.max(temp,max); } } return max; } private int searchMaxPath(int[][] matrix,int row,int col,int pre){ if (row < 0 || col < 0 || row >= matrix.length || col >= matrix.length){ return 0; } if (matrix[row][col] <= pre){ return 0; } // 表中存在,直接返回 if (paths[row][col] > 0){ return paths[row][col]; } int max = 0; int temp = 0; // 点(row,col)往上走的最长路径 temp = searchMaxPath(matrix,row-1,col,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往下走的最长路径 temp = searchMaxPath(matrix,row+1,col,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往左走的最长路径 temp = searchMaxPath(matrix,row,col-1,matrix[row][col]); max = Math.max(temp,max); // 点(row,col)往右走的最长路径 temp = searchMaxPath(matrix,row,col+1,matrix[row][col]); max = Math.max(temp,max); // 记录 paths[row][col] = max + 1; return paths[row][col]; } }
- 时间复杂度:,双重循环为mn,而dfs近乎;
- 空间复杂度:,递归深度不超过mn,记忆表大小为mn。