描述
给定一个 n 行 m 列矩阵 matrix ,矩阵内所有数均为非负整数。 你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。并输出这条最长路径的长度。
这个路径必须满足以下条件:
-
对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外。
-
你不能走重复的单元格。即每个格子最多只能走一次。
数据范围:1≤n,m≤10001≤n,m≤1000,0≤matrix[i][j]≤10000≤matrix[i][j]≤1000
进阶:空间复杂度 O(nm)O(nm) ,时间复杂度 O(nm)O(nm)
例如:当输入为[[1,2,3],[4,5,6],[7,8,9]]时,对应的输出为5,
其中的一条最长递增路径如下图所示:
示例1
输入:
[[1,2,3],[4,5,6],[7,8,9]]
返回值:
5
说明:
1->2->3->6->9即可。当然这种递增路径不是唯一的。
示例2
输入:
[[1,2],[4,3]]
返回值:
4
说明:
1->2->3->4
备注:
矩阵的长和宽均不大于1000,矩阵内每个数不大于1000
记忆化搜索
-
我们发现,如果我们在某一个过程中遍历到了(x,y)这个位置的时候,我们可以利用递归计算出这个位置开始可以走多少步。那么如果我们下次计算新的起始点的时候再走到了这个位置的时候,我们没有必要继续执行递归的操作了,我们可以直接利用之前递归得到的结果拿来用就行了。但是这样的方法我们需要额外开空间存储所有的位置的状态,这就是典型的空间换时间的做法,如果到了某一个位置的时候已经计算过,我们直接用,这样就减少了遍历的必要。
-
代码如下
- 每个位置只需要遍历一次,所以总的时间复杂度为O(nm)O(nm)O(nm)
- 需要存储每个位置为起始点的时候的状态,同时递归的层数为nm,空间复杂为O(nm)O(nm)O(nm)
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 递增路径的最大长度
* @param matrix int整型vector<vector<>> 描述矩阵的每个数
* @return int整型
*/
int dfs(vector<vector<int> > &mat,vector<vector<int> > &dp,int x,int y,int pre){
if(mat[x][y]<=pre){
return 0;
}
int n=mat.size();
int m=mat[0].size();
// 进行记忆化搜索
if(dp[x][y]!=-1){
return dp[x][y];
}
int mx=0;
// 分别向四个方向进行转移
if(x+1<n){
mx=max(mx,dfs(mat,dp,x+1,y,mat[x][y]));
}
if(x-1>=0){
mx=max(mx,dfs(mat,dp,x-1,y,mat[x][y]));
}
if(y-1>=0){
mx=max(mx,dfs(mat,dp,x,y-1,mat[x][y]));
}
if(y+1<m){
mx=max(mx,dfs(mat,dp,x,y+1,mat[x][y]));
}
// 更新这个位置的状态
dp[x][y]=mx+1;
return mx+1;
}
int solve(vector<vector<int> >& matrix) {
// write code here
int n=matrix.size();
// 特判为空的情况
if(n==0){
return 0;
}
int m=matrix[0].size();
// 初始化操作
vector<vector<int> > dp(n,vector<int> (m,-1));
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
ans=max(ans,dfs(matrix,dp,i,j,-1));
}
}
return ans;
}
};