BM61. [矩阵最长递增路径]
https://www.nowcoder.com/exam/oj?tab=%E7%AE%97%E6%B3%95%E7%AF%87&topicId=295
BM61. 矩阵最长递增路径
题目的主要信息:
- 矩阵内是非负数,求最长的递增路径的长度
- 移动方向可以是上下左右,不能超出边界,这将是递归的判定条件
- 同一条路径不能有重复的单元格,需要有记忆
方法一:深度优先搜索
具体做法:
使用一个dp二维数组作为缓存,记忆该单元格是否访问过的同时记录以该单元为起点的最长路径是多少(0就是未访问过),由此深度优先搜索的时候就不会重复计算很多内容。
遍历矩阵,对矩阵中每一个点进行dfs寻找最长递增路径,每次更新最大值即可得到。
class Solution { public: int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};//记录四个方向 int n, m; //深度优先搜索,返回最大单元格数 int dfs(vector<vector<int> > &matrix, vector<vector<int> > &dp,int i, int j) { if (dp[i][j] != 0) return dp[i][j]; dp[i][j]++; for (int k = 0; k < 4; k++) { int nexti = i + dirs[k][0]; int nextj = j + dirs[k][1]; //判断条件 if (nexti >= 0 && nexti < n && nextj >= 0 && nextj < m && matrix[nexti][nextj] > matrix[i][j]) { dp[i][j] = max(dp[i][j], dfs(matrix, dp, nexti, nextj) + 1); } } return dp[i][j]; } int solve(vector<vector<int> >& matrix) { if (matrix.size() == 0 || matrix[0].size() == 0) //矩阵不为空 return 0; int res = 0; n = matrix.size(); m = matrix[0].size(); vector<vector<int> > dp (n, vector <int> (m)); //i,j处的单元格拥有的最长递增路径 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { res = max(res, dfs(matrix, dp, i, j)); //更新最大值 } } return res; } };
复杂度分析:
- 时间复杂度:,mn分别为矩阵的两边,遍历整个矩阵
- 空间复杂度:,辅助矩阵
方法二:广度优先搜索
我们可以将矩阵看成是一个有向图,计算每个结点(单元格)所对应的出度(符合边界条件且递增)。对于作为边界条件的单元格,它的值比所有的相邻单元格的值都要大,因此作为边界条件的单元格的出度都为0。
利用拓扑排序的思想,从所有出度为0的单元格开始进行广度优先搜索,每次搜索都会遍历当前层的所有单元格,更新其余单元格的出度,并将出度变为0的单元格加入下一层搜索。当搜索结束时,搜索的总层数即为矩阵中的最长递增路径的长度。
具体做法:
利用一个二维矩阵记录每个单元格的出度,借助队列来广度优先搜索,队列中每次加入出度为0的点,即路径最远点,每次从A点到B点,便将A点出度减一。搜索结束时,自然得到搜索层数即最长递增路径长度。
class Solution { public: int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};//记录四个方向 int n, m; int solve(vector<vector<int> >& matrix) { if (matrix.size() == 0 || matrix[0].size() == 0) //空矩阵 return 0; n = matrix.size(); m = matrix[0].size(); vector<vector<int> > outdegrees(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 nexti = i + dirs[k][0]; int nextj = j + dirs[k][1]; if (nexti >= 0 && nexti < n && nextj >= 0 && nextj < m && matrix[nexti][nextj] > matrix[i][j]) { outdegrees[i][j]++; //符合条件,记录出度 } } } } queue <pair<int, int> > q; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) if (outdegrees[i][j] == 0) q.push({i, j}); //找到出度为0的入队列 int res = 0; while (!q.empty()) { res++; int size = q.size(); for (int x = 0; x < size; x++) { pair<int, int> temp = q.front(); q.pop(); int i = temp.first; int j = temp.second; for (int k = 0; k < 4; k++) { //四个方向 int nexti = i + dirs[k][0]; int nextj = j + dirs[k][1]; //逆向搜索,所以下一步是小于 if (nexti >= 0 && nexti < n && nextj >= 0 && nextj < m && matrix[nexti][nextj] < matrix[i][j]) { outdegrees[nexti][nextj]--; //符合条件,出度递减 if (outdegrees[nexti][nextj] == 0) { q.push({nexti, nextj}); } } } } } return res; } };
复杂度分析:
- 时间复杂度:,mn分别为矩阵的两边,遍历整个矩阵
- 空间复杂度:,辅助矩阵