矩阵中的最长递增子序列
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; } };
所以说,编程能力真的很重要啊,一份好的代码总是思路足够清晰,没有冗余计算的。
以上是关于矩阵中的最长递增子序列的主要内容,如果未能解决你的问题,请参考以下文章