矩阵中的最长递增子序列

Posted fanmu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了矩阵中的最长递增子序列相关的知识,希望对你有一定的参考价值。

和上一道  最长上升子序列 思路一样,不过还是从最笨的方法开始吧,也算是记录一下思考过程。

最开始的想法是,对矩阵的每个点都来一次回溯,得到从这个点开始的最长上升子序列长度。回溯的思路就是对上下左右遍历,利用到递归,停止遍历的条件是四周的数都比它大。代码如下:

class Solution1 {
public:
    // 对矩阵的每个点直接利用回溯法 超时了 
    void FindMaxLength(vector< vector<int> >& matrix, vector< vector<int> >& visited, int& maxLength, int length, int i, int j){
        if(i<0 || i>(matrix.size() - 1) || j<0 || j>(matrix[0].size() - 1)) return;
        if(i>0 && visited[i-1][j] == 0 && matrix[i-1][j] > matrix[i][j]){
            visited[i-1][j] = 1;
            length++;
            maxLength = max(length, maxLength);
            FindMaxLength(matrix, visited, maxLength, length, i-1, j);
            length--;
            visited[i-1][j] = 0;
        }
        if(i<(matrix.size() - 1) && visited[i+1][j] == 0 && matrix[i+1][j] > matrix[i][j]){
            visited[i+1][j] = 1;
            length++;
            maxLength = max(length, maxLength);
            FindMaxLength(matrix, visited, maxLength, length, i+1, j);
            length--;
            visited[i+1][j] = 0;
        }
        if(j>0 && visited[i][j-1] == 0 && matrix[i][j-1] > matrix[i][j]){
            visited[i][j-1] = 1;
            length++;
            maxLength = max(length, maxLength);
            FindMaxLength(matrix, visited, maxLength, length, i, j-1);
            length--;
            visited[i][j-1] = 0;
        }
        if(j<(matrix[0].size() - 1) && visited[i][j+1] == 0 && matrix[i][j+1] > matrix[i][j]){
            visited[i][j+1] = 1;
            length++;
            maxLength = max(length, maxLength);
            FindMaxLength(matrix, visited, maxLength, length, i, j+1);
            length--;
            visited[i][j+1] = 0;
        }
        return;
    }
    int longestIncreasingPath(vector< vector<int> >& matrix) {
        if(matrix.empty()) return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        int maxLength = 1;
        int length;
        vector< vector<int> > visited(m, vector<int>(n,0));
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                length = 1;
                FindMaxLength(matrix, visited, maxLength, length, i, j);
            }
        }
        return maxLength;
    }
};

嗯...超时了。其实这里有不少冗余计算,比如说往上遍历到某个点时,如果这个点之前计算过最长上升子序列长度,那就可以直接用了,没必要再次计算,也就是可以用到动态规划的思路。代码如下:

class Solution2 {
public:
    //还是超时了  
    void FindMaxLength(vector< vector<int> >& matrix, int& maxLength, int length, vector< vector<int> > Length, int i, int j){
//        if(i<0 || i>(matrix.size() - 1) || j<0 || j>(matrix[0].size() - 1)) return;
        if(i>0 && matrix[i-1][j] > matrix[i][j]){
            if(Length[i-1][j] != 0){
                maxLength = max(length+Length[i-1][j], maxLength);
            }
            else{
                length++;
                maxLength = max(length, maxLength);
                FindMaxLength(matrix, maxLength, length, Length, i-1, j);
                length--;
            }
        }
        if(i<(matrix.size() - 1) && matrix[i+1][j] > matrix[i][j]){
            if(Length[i+1][j] != 0){
                maxLength = max(length+Length[i+1][j], maxLength);
            }
            else{
                length++;
                maxLength = max(length, maxLength);
                FindMaxLength(matrix, maxLength, length, Length, i+1, j);
                length--;
            }
        }
        if(j>0 && matrix[i][j-1] > matrix[i][j]){
            if(Length[i][j-1] != 0){
                maxLength = max(length+Length[i][j-1], maxLength);
            }
            else{
                length++;
                maxLength = max(length, maxLength);
                FindMaxLength(matrix, maxLength, length, Length, i, j-1);
                length--;
            }
        }
        if(j<(matrix[0].size() - 1) && matrix[i][j+1] > matrix[i][j]){
            if(Length[i][j+1] != 0){
                maxLength = max(length+Length[i][j+1], maxLength);
            }
            else{
                length++;
                maxLength = max(length, maxLength);
                FindMaxLength(matrix, maxLength, length, Length, i, j+1);
                length--;
            }
        }
        return;
    }
    int longestIncreasingPath(vector< vector<int> >& matrix) {
        if(matrix.empty()) return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        int maxLengthOfMatrix = 1;
        int maxLengthOfPoint = 1;
        vector< vector<int> > Length(m, vector<int>(n,0));
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                maxLengthOfPoint = 1;
                FindMaxLength(matrix, maxLengthOfPoint, 1, Length, i, j);
                Length[i][j] = maxLengthOfPoint;
                maxLengthOfMatrix = max(maxLengthOfMatrix, maxLengthOfPoint);
            }
        }
        return maxLengthOfMatrix;
    }
};

嗯...还是超时了。超时的原因是没有真正贯彻落实动态规划,因为上面的代码里记录最长子序列记录得不到位。实际上在对任一个点进行回溯搜索时,途径的点都是计算过最长上升子序列的,因此需要都记录下来,而在上面的代码中只对已经进行回溯的点进行记录。最终版代码如下

class Solution {
public:
    vector< vector<int> > Length;
    int FindMaxLength(vector< vector<int> >& matrix, int i, int j){
        if(Length[i][j]) return Length[i][j];
        int maxLength = 0;
        if(i>0 && matrix[i-1][j] > matrix[i][j]){
            maxLength = max(maxLength, FindMaxLength(matrix, i-1, j));
        }
        if(i<(matrix.size() - 1) && matrix[i+1][j] > matrix[i][j]){
            maxLength = max(maxLength, FindMaxLength(matrix, i+1, j));
        }
        if(j>0 && matrix[i][j-1] > matrix[i][j]){
            maxLength = max(maxLength, FindMaxLength(matrix, i, j-1));
        }
        if(j<(matrix[0].size() - 1) && matrix[i][j+1] > matrix[i][j]){
            maxLength = max(maxLength, FindMaxLength(matrix, i, j+1));
        }
        Length[i][j] = maxLength + 1;
        return Length[i][j];
    }
    int longestIncreasingPath(vector< vector<int> >& matrix) {
        if(matrix.empty()) return 0;
        int m = matrix.size();
        int n = matrix[0].size();
        int maxLengthOfMatrix = 1;
        Length.resize(m, vector<int>(n, 0));
        for(int i = 0;i<m;i++){
            for(int j = 0;j<n;j++){
                Length[i][j] = FindMaxLength(matrix, i, j);
                maxLengthOfMatrix = max(maxLengthOfMatrix, Length[i][j]);
            }
        }
        return maxLengthOfMatrix;
    }
};

所以说,编程能力真的很重要啊,一份好的代码总是思路足够清晰,没有冗余计算的。

 

以上是关于矩阵中的最长递增子序列的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第五十二天 | 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

LeetCode刷题 最长递增子序列

Leetcode 300. 最长递增子序列

笔试题1:最长严格递增子序列

Java 求解最长递增子序列

Java 求解最长递增子序列