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

这里是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;
    }

};

你可能感兴趣的:(LeetCode,算法设计,C++,DFS,动态规划)