【LeetCode】329.矩阵中的最长递增路径

104 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情

题目

给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。

对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。

示例 1

输入:matrix = [[9,9,4],[6,6,8],[2,1,1]]
输出:4 
解释:最长递增路径为 [1, 2, 6, 9]。

示例 2

img

输入: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;
    }
};

结语

业精于勤,荒于嬉;行成于思,毁于随。