[LeetCode]329. Longest Increasing Path in a Matrix —— DFS和动态规划

时间:2022-09-06 19:25:53

这里是LeeTioN的博客

这两天一直在刷Top interview 中的BFS和DFS的题目,这道题我一开始只用了深度优先搜索,发现快到最后的一个case超时了,于是看了Discuss里面,大牛们用到了动态规划的思想,于是恍然大悟。

这道题的目的是给定一个整形数的矩阵,让我们求出一个最长的递增序列,序列是通过数字上下左右四个方向联系起来,首先让我想到的就是DFS方法,当matrix[i][j]想走到下一步时,只有比它大的数,才能走下一步。所以这里我们就不用 Visit[] 数组来记录哪些点已被访问,因为只能走比原来大的数的点。

我一开始将矩阵看成一个图,将入度表示为一个点周围比他小的数的个数,出度表示为一个点周围比他大的数的个数,每当访问到出度为0的点,即停止递归。

class Solution {//超时代码
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
int nr = matrix.size();
if(nr == 0){
return 0;
}
int nc = matrix[0].size();
int max = 1;
vector<vector<int>> indegree;
indegree.resize(nr, vector<int>(nc, 0));
vector<vector<int>> outdegree;
outdegree.resize(nr, vector<int>(nc, 0));
for(int r = 0; r < nr; r++){//计算每个点的入度和出度
for(int c = 0; c < nc; c++){
if(r > 0){
if(matrix[r-1][c] > matrix[r][c]){
outdegree[r][c]++;
}
if(matrix[r-1][c] < matrix[r][c]){
indegree[r][c]++;
}
}
if(r < nr - 1){
if(matrix[r+1][c] > matrix[r][c]){
outdegree[r][c]++;
}
if(matrix[r+1][c] < matrix[r][c]){
indegree[r][c]++;
}
}
if(c > 0){
if(matrix[r][c-1] > matrix[r][c]){
outdegree[r][c]++;
}
if(matrix[r][c-1] < matrix[r][c]){
indegree[r][c]++;
}
}
if(c < nc - 1){
if(matrix[r][c+1] > matrix[r][c]){
outdegree[r][c]++;
}
if(matrix[r][c+1] < matrix[r][c]){
indegree[r][c]++;
}
}
}
}

for(int r = 0; r < nr; r++){
for(int c = 0; c < nc; c++){//从入度为0(局部最小)、出度大于0(有路可走)的点开始查找
if(indegree[r][c] == 0 && outdegree[r][c] > 0){
max = std::max(max, 1 + dfs(r, c, matrix, outdegree));
}
}
}
return max;
}

int dfs(int r, int c, vector<vector<int>>& matrix, vector<vector<int>>& outdegree){
int nr = matrix.size();
int nc = matrix[0].size();
int max = 1;
if(outdegree[r][c] == 0){//如果出度为0,即找不到周围比自己大的数,返回0
return 0;
}
//分别向四个方向探索
if(r > 0 && matrix[r][c] < matrix[r-1][c]){
max = std::max(max, 1 + dfs(r - 1, c, matrix, outdegree));
}
if(c > 0 && matrix[r][c] < matrix[r][c-1]){
max = std::max(max, 1 + dfs(r, c - 1, matrix, outdegree));
}
if(r < nr - 1 && matrix[r][c] < matrix[r+1][c]){
max = std::max(max, 1 + dfs(r + 1, c, matrix, outdegree));
}
if(c < nc - 1 && matrix[r][c] < matrix[r][c+1]){
max = std::max(max, 1 + dfs(r, c + 1, matrix, outdegree));
}
return max;
}

};

这个代码超时的代码主要问题出在,反复地去重新计算一些已经算过的点的最大路径(就跟斐波那契数列的递归方法一样),这样重复计算了很多次,导致超时。而解决办法即是记录那些已经被计算出的最长路径的点,用一个二维数组来存储。

以下为改进代码

class Solution {
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
int nr = matrix.size();
if(nr == 0){
return 0;
}
int nc = matrix[0].size();
int max = 1;
//创建dp数组,记录每个位置的最大路径长度,初始化为0
vector<vector<int>> dp(nr, vector<int>(nc, 0));
for(int r = 0; r < nr; r++){
for(int c = 0; c < nc; c++){
max = std::max(max, dfs(r, c, matrix, dp));
//这里直接遍历所有点,没有像上一版的挑合适的点来递归,时间上是允许的
}
}
return max;
}

int dfs(int r, int c, vector<vector<int>>& matrix, vector<vector<int>>& dp){
if(dp[r][c] != 0){//不为0表示已经计算过
return dp[r][c];
}
int nr = matrix.size();
int nc = matrix[0].size();
int max = 1;
if(r > 0 && matrix[r][c] < matrix[r-1][c]){
max = 1 + dfs(r - 1, c, matrix, dp);
}
if(c > 0 && matrix[r][c] < matrix[r][c-1]){
max = std::max(max, 1 + dfs(r, c - 1, matrix, dp));
}
if(r < nr - 1 && matrix[r][c] < matrix[r+1][c]){
max = std::max(max, 1 + dfs(r + 1, c, matrix, dp));
}
if(c < nc - 1 && matrix[r][c] < matrix[r][c+1]){
max = std::max(max, 1 + dfs(r, c + 1, matrix, dp));
}
dp[r][c] = max;//记录
return max;
}

};