一、前言
问题来源LeetCode 329,难度:困难
二、题目
给定一个整数矩阵,找出最长递增路径的长度。对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。
示例 1:
输入: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
输出: 4
解释: 最长递增路径为 [1, 2, 6, 9]。
示例 2:
输入: nums =
[
[3,4,5],
[3,2,6],
[2,2,1]
]
输出: 4
解释: 最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。
三、思路
三种解法
3.1 方法一:朴素的深度优先搜索
时间复杂度:O(2^(m+n)),空间复杂度:O(mn)
3.2 方法二:带备忘录的深度优先搜索
时间复杂度:O(mn),空间复杂度:O(mn)
3.3 方法三:拓扑排序+记忆化搜索
时间复杂度:O(mn),空间复杂度:O(mn)
拓扑排序步骤:
- 从DGA图中找到一个没有前驱的顶点输出。(可以遍历,也可以用优先队列维护)
- 删除以这个点为起点的边。(它的指向的边删除,为了找到下个没有前驱的顶点)
- 重复上述,直到最后一个顶点被输出。如果还有顶点未被输出,则说明有环!
输出并删除没有前驱的顶点,一直重复这个过程。对应本题中整数矩阵,没有前驱的顶点就是最小的数,找到最小的数就可以确定它上下左右位置上的数最长路径。
拓扑排序原理可以参考:https://www.cnblogs.com/bigsai/p/11489260.html
四、编码技巧
在判断上下左右坐标的时候,可以定义一个数组保存上下左右移动的坐标增量,这样就可以通过循环来进行坐标点判断。而不用进行四次坐标点判断了。
static const int dirs[4][2] = { {0, 1}, {-1, 0}, {0, -1}, {1, 0} }; // 分别是 向后、向下、向左、向上
for (int i = 0; i < 4; ++i)
{
int nh = ph + dirs[i][0];
int nx = px + dirs[i][1];
if (nh >= 0 && nh <= maxH && nx >= 0 && nx <= maxX && matrix[ph][px] < matrix[nh][nx])
{
int ret = longestIncreasingPath(matrix, nh, nx) + 1;
maxPath = max(maxPath, ret);
}
}
五、编码实现
//==========================================================================
/**
* @file : 329_LongestIncreasingPath.h
* @title: 矩阵中的最长递增路径
* @purpose : 给定一个整数矩阵,找出最长递增路径的长度。对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。
*
* 示例 1:
* 输入: nums =
* [