携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
题目
给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。
示例 1
输入:matrix = [[9,9,4],[6,6,8],[2,1,1]]
输出:4
解释:最长递增路径为 [1, 2, 6, 9]。
示例 2
输入:matrix = [[3,4,5],[3,2,6],[2,2,1]]
输出:4
解释:最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。
示例 3
输入:matrix = [[1]]
输出:1
提示
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 200
- 0 <=
matrix[i][j]<= 2^31 - 1
题解
思路
将矩阵看作是一个有向图,计算每个单元格对应的出度,即有多少条边从该节点出发,也就是相邻的四个顶点有几个点比该点大。
边界条件是出度为0的点,若为路径,必为路径结尾。
基于出度的概念,可以使用拓扑排序求解,从所有出度为0的单元格开始广度优先搜索,每一轮都会遍历当前队列中的所有节点,然后更新周围的节点,并将出度为0的节点加入下一层。这样,分别遍历出度为0,相邻且出度为1,相邻且出度为2...的节点,当遍历结束时,搜索的总层数即为答案。
代码
class Solution {
// 上下左右四个方向
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
if (matrix.size() == 0 || matrix[0].size() == 0) return 0;
int rows = matrix.size(), columns = matrix[0].size();
// 存储出度
vector<vector<int>> outdegrees(rows, vector<int>(columns, 0));
queue<pair<int, int>> q;
// 先更新每个点的出度, 并将更新后出度仍为0的点加入队列
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
for (int direction = 0; direction < 4; direction++) {
int newRow = row + dirs[direction][0], newColumn = column + dirs[direction][1];
if (newRow>=0 && newRow < rows && newColumn>=0 && newColumn<columns && matrix[newRow][newColumn] > matrix[row][column]) {
++outdegrees[row][column];
}
}
// cout << outdegrees[row][column] << " ";
if (outdegrees[row][column] == 0) q.push({row, column});
}
// cout << endl;
}
// 开始分层遍历,并记录层数。
int ans = 0;
while (!q.empty()) {
++ans;
int size = q.size();
for (int i = 0; i < size; i++) {
auto cell = q.front(); q.pop();
int row = cell.first, column = cell.second;
for (int direction = 0; direction < 4; direction++) {
int newRow = row + dirs[direction][0], newColumn = column + dirs[direction][1];
if (newRow>=0 && newRow < rows && newColumn>=0 && newColumn<columns && matrix[newRow][newColumn] < matrix[row][column]) {
--outdegrees[newRow][newColumn];
if (outdegrees[newRow][newColumn] == 0) q.push({newRow, newColumn});
}
}
}
}
return ans;
}
};
结语
业精于勤,荒于嬉;行成于思,毁于随。