最长递减路径节点数查找问题 | 豆包MarsCode AI刷题

114 阅读4分钟

最长递减路径节点数查找问题

本篇文章探讨了在一个二维整数网格中寻找最长递减路径的问题。小C希望找到一条路径,使得路径上的每个节点值都严格递减,并且只能上下左右移动。通过动态规划结合深度优先搜索(DFS)的方式,我们定义了状态并利用记忆化优化了计算过程,以有效找出从任意节点出发的最长递减路径的长度。最后,通过遍历整个网格,计算出最长递减路径的节点数量。

一、问题描述

小C正在研究一个二维整数网格Grid,他的目标是找到一条包含最多节点的路径,这条路径上每个节点的值都必须严格递减。小C只能在网格内上下左右移动,不能走对角线,也不能走出网格的边界。

小C想知道,经过这种规则能找到的最长递减路径的节点个数是多少。

例如,给定一个网格:

9 6 4
5 6 7
2 1 1

最长的递减路径是 [7, 6, 5, 2, 1],这条路径的节点数为5。

二、解题思路

为了找到最长的递减路径,我们可以使用动态规划和深度优先搜索的结合方法。主要思路如下:

  1. 定义状态:我们使用一个二维数组 dp 来存储从每个节点开始的最长递减路径的长度。
  2. DFS与记忆化:使用 DFS 遍历每个节点,并根据其相邻节点的值来递归计算最长递减路径。在递归过程中,利用 dp 数组进行记忆化,以避免重复计算。
  3. 边界条件:在 DFS 时,只能向上下左右相邻的节点移动,且当前节点的值必须大于相邻节点的值才能形成递减路径。
  4. 结果更新:通过对所有节点调用 DFS 函数,更新并记录得到的最大路径长度。

三、解题步骤

  1. 初始化

    • 创建一个存储网格行数和列数的变量。
    • 初始化一个 dp 数组,用于存储每个节点的最长递减路径长度。
  2. 定义 DFS 函数

    • 在 DFS 函数中,检查当前节点是否已经计算过。如果已经计算,则直接返回该节点的最长路径长度。
    • 否则,遍历当前节点的四个方向的邻接节点,检查它们的值是否小于当前节点的值,如果是,则递归调用 DFS。
  3. 遍历所有节点

    • 对网格中的每个节点调用 DFS 函数,更新最长路径的结果。
  4. 输出结果

    • 返回最终找到的最长递减路径的节点数。

四、代码实现

以下是使用Go实现的代码:

func longestDecreasingPath(grid [][]int) int {
	if len(grid) == 0 || len(grid[0]) == 0 {
		return 0
	}

	rows := len(grid)
	cols := len(grid[0])
	dp := make([][]int, rows) // 用于存储每个节点的最长递减路径长度
	for i := range dp {
		dp[i] = make([]int, cols)
	}

	var dfs func(x, y int) int
	dfs = func(x, y int) int {
		if dp[x][y] != 0 { // 如果已经计算过,直接返回
			return dp[x][y]
		}

		maxLength := 1 // 当前节点至少包含自己
		// 定义方向数组:上下左右
		directions := [][2]int{
			{1, 0},  // 下
			{-1, 0}, // 上
			{0, 1},  // 右
			{0, -1}, // 左
		}

		for _, direction := range directions {
			nx, ny := x+direction[0], y+direction[1] // 计算相邻节点坐标
			if nx >= 0 && nx < rows && ny >= 0 && ny < cols && grid[nx][ny] < grid[x][y] {
				maxLength = max(maxLength, 1+dfs(nx, ny)) // 更新最大长度
			}
		}
		
		dp[x][y] = maxLength // 存储结果
		return maxLength
	}

	result := 0
	for i := 0; i < rows; i++ {
		for j := 0; j < cols; j++ {
			result = max(result, dfs(i, j)) // 更新全局最大值
		}
	}

	return result
}

// 辅助函数:获取较大值
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

五、复杂度分析

  • 时间复杂度:O(m * n),其中 m 和 n 分别是网格的行数和列数。每个节点最多被访问一次,因此总的复杂度是 O(m * n)。
  • 空间复杂度:O(m * n),用于存储 DP 数组和递归栈空间。

六、总结

在解决最长递减路径的问题时,利用 DFS 与动态规划的组合,有效地找到符合条件路径长度。通过记忆化存储中间结果,可以显著提高算法效率。这种方法不仅适用于本问题,还可以扩展到其他图形遍历相关的问题中。