数据结构与算法之 leetcode 动态规划不同路径 III 记忆化搜索

数据结构与算法阿木 发布于 5 天前 2 次阅读


摘要:

动态规划(Dynamic Programming,DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学等领域中广泛应用的方法。它通过将复杂问题分解为更小的子问题,并存储这些子问题的解以避免重复计算,从而提高算法的效率。本文将以LeetCode上的“不同路径 III”问题为例,探讨动态规划与记忆化搜索在解决此类问题中的应用。

一、问题背景

LeetCode上的“不同路径 III”问题如下:

在一个有m行n列的网格中,每个单元格有两种可能的状态:0(空)和1(障碍物)。开始时,你位于左上角(0,0)的单元格中,你的目标是到达右下角(m-1,n-1)的单元格。每次移动,你可以向上、下、左或右移动一步。你只能通过没有障碍物的单元格。每一步移动都会使你离目标更近一步。返回从左上角到右下角的最少移动次数。

二、动态规划与记忆化搜索概述

1. 动态规划

动态规划是一种将复杂问题分解为更小的子问题,并存储这些子问题的解以避免重复计算的方法。它通常用于解决具有重叠子问题和最优子结构的问题。

2. 记忆化搜索

记忆化搜索是一种将递归搜索与动态规划相结合的方法。它通过存储已经计算过的子问题的解来避免重复计算,从而提高算法的效率。

三、问题分析与解决方案

1. 状态定义

定义dp[i][j][k]为到达点(i,j)时,已经走过的障碍物数量为k的不同路径数量。

2. 状态转移方程

- 如果当前单元格是障碍物,则dp[i][j][k] = 0。

- 如果当前单元格是空单元格,则dp[i][j][k] = dp[i-1][j][k-1] + dp[i][j-1][k-1] + dp[i+1][j][k-1] + dp[i][j+1][k-1]。

3. 初始化

- dp[0][0][0] = 1,表示从起点开始,没有走过任何障碍物。

4. 递归函数

python

def uniquePathsIII(grid):


m, n = len(grid), len(grid[0])


empty_count = 0


dp = [[[0] (m n + 1) for _ in range(n)] for _ in range(m)]



def dfs(i, j, k):


if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 1 or dp[i][j][k] != 0:


return 0


if i == m - 1 and j == n - 1:


return 1 if k == empty_count else 0


dp[i][j][k] = (dfs(i + 1, j, k + 1) + dfs(i, j + 1, k + 1) +


dfs(i - 1, j, k + 1) + dfs(i, j - 1, k + 1)) % (109 + 7)


return dp[i][j][k]



for i in range(m):


for j in range(n):


if grid[i][j] == 0:


empty_count += 1


dp[i][j][0] = 1



return dfs(0, 0, 1)


四、总结

本文以LeetCode上的“不同路径 III”问题为例,介绍了动态规划与记忆化搜索在解决此类问题中的应用。通过定义状态、状态转移方程和初始化,我们能够有效地计算出从起点到终点的不同路径数量。在实际应用中,动态规划与记忆化搜索可以帮助我们解决许多复杂问题,提高算法的效率。

五、扩展

1. 在实际应用中,我们可以根据问题的特点选择合适的动态规划方法,如自顶向下、自底向上等。

2. 记忆化搜索可以与回溯算法、深度优先搜索等相结合,解决更复杂的问题。

3. 动态规划与记忆化搜索在解决组合优化问题时具有广泛的应用,如背包问题、旅行商问题等。

相信读者对动态规划与记忆化搜索在解决LeetCode“不同路径 III”问题中的应用有了更深入的了解。在实际编程过程中,我们可以灵活运用这些方法,提高算法的效率。