题意:
给定一个整数矩阵,找出最长递增路径的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。
解法1 : 首先第一个想到的是用dfs搜索,从每一个点出发,每次搜索会有一个最大递增长度,然后取max即可。
代码:
class Solution {
public:
int maxlen=0;
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int dfs(vector<vector<int>>& matrix,int x,int y,int n,int m)
{
int mx=0;
for(int i=0;i<4;i++)
{
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(tx<0||tx>=n||ty<0||ty>=m)continue;
if(matrix[tx][ty]>matrix[x][y])
{
mx=max(mx,dfs(matrix,tx,ty,n,m)+1);
}
}
return mx;
}
int longestIncreasingPath(vector<vector<int>>& matrix) {
int len=matrix.size();
if(len==0)return 0;
for(int i=0;i<len;i++)
{
for(int j=0;j<matrix[i].size();j++)
{
maxlen=max(maxlen,dfs(matrix,i,j,len,matrix[i].size())+1);
}
}
return maxlen;
}
};
提交发现,只通过了135/138 ,时间超出了题目限制
所以说暴力搜索不能解决全部的问题,我们思考记忆化去搜索来优化算法
如果我们能记录下当前位置的最大长度,那么只需要看看当前位置的最大长度是否已经计算出了,如果已经计算出了,我们就return,如果没有计算出来,那么我从1长度开始搜索,这样大大加快运行速度。
AC代码:
class Solution {
public:
int maxlen=0;
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int mx[300][300];
int dfs(vector<vector<int>>& matrix,int x,int y,int n,int m)
{
if(mx[x][y]!=0)
{
return mx[x][y];
}
mx[x][y]++;
for(int i=0;i<4;i++)
{
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(tx<0||tx>=n||ty<0||ty>=m)continue;
if(matrix[tx][ty]>matrix[x][y])
{
mx[x][y]=max(mx[x][y],dfs(matrix,tx,ty,n,m)+1);
}
}
return mx[x][y];
}
int longestIncreasingPath(vector<vector<int>>& matrix) {
int len=matrix.size();
if(len==0)return 0;
for(int i=0;i<len;i++)
{
for(int j=0;j<matrix[i].size();j++)
{
maxlen=max(maxlen,dfs(matrix,i,j,len,matrix[i].size()));
}
}
return maxlen;
}
};
对比2个代码,区别就是有没有记忆化,第二种采用二维数组去记录每个点的最大递增路径,大大减少了搜索的次数。
方法2: 也是官方的一种奇妙的解法: 拓扑排序
我们可以把图当做一个有向图来看,当前节点(i,j)四个方向满足递增的序列,那么 (i,j)这个点的出度++ 。
看下面一个例子
[[1,2]]
[[2,3]]
例如 i=0,j=0;
满足条件(指的的递增这个条件)的话有 点(0,1) 点(1,0)
所以说 out[0][0]=2 // out 表示出度
由于所有出度为0的点,都是最长递增序列的最后一个点,
我们可以凭借出度来进行拓扑排序。 那么进行了几轮拓扑排序,就是我们要的答案,也就是最长递增子序列
AC代码:
class Solution {
public:
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int longestIncreasingPath(vector<vector<int>>& matrix) {
int n=matrix.size();
if(n==0)return 0;
int m=matrix[0].size();
auto o=vector<vector<int>>(n,vector<int>(m));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
for(int k=0;k<4;k++)
{
int tx=i+dir[k][0];
int ty=j+dir[k][1];
if(tx<0||tx>=n||ty<0||ty>=m)continue;
if(matrix[tx][ty]>matrix[i][j])
{
++o[i][j];
}
}
}
}
queue<pair<int,int>>q;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(o[i][j]==0)
{
q.push({i,j});
}
}
}
int ans=0;
while(!q.empty())
{
int siz=q.size();
ans++;
while(siz--)
{
auto x=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int tx=x.first+dir[i][0];
int ty=x.second+dir[i][1];
if(tx<0||tx>=n||ty<0||ty>=m||matrix[tx][ty]>=matrix[x.first][x.second])continue;
o[tx][ty]--;
if(o[tx][ty]==0)
{
q.push({tx,ty});
}
}
}
}
return ans;
}
};