1. 动态规划路径问题入门
动态规划是解决路径类问题的利器,尤其适合处理网格中的移动计数问题。今天我要分享的是两个经典题目:不同路径和带障碍物的不同路径。这两个问题在面试中出现的频率相当高,也是理解动态规划思想的绝佳案例。
作为算法工程师,我经常需要处理类似的路径规划问题。动态规划之所以高效,是因为它避免了重复计算,通过存储中间结果来提升效率。在网格路径问题中,这种优势尤为明显。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 不同路径问题解析
2.1 问题描述与理解
题目要求计算从m×n网格的左上角到右下角的所有可能路径数,每次只能向右或向下移动。这是一个典型的组合数学问题,也可以用动态规划优雅解决。
我初次遇到这个问题时,第一反应是用递归暴力求解。但很快发现当网格变大时,递归的效率极低。这时动态规划的优势就显现出来了——它可以将时间复杂度从指数级降到多项式级。
2.2 动态规划解法详解
2.2.1 状态定义
我们定义dp[i][j]表示到达(i,j)位置的路径总数。这个定义很直观,因为我们需要的就是到达终点的路径数。
在实际编码中,我习惯将dp数组定义为(m+1)×(n+1)大小,这样可以利用第0行和第0列作为边界条件,简化初始化过程。
2.2.2 状态转移方程
状态转移方程是动态规划的核心。对于每个位置(i,j),只能从上方(i-1,j)或左方(i,j-1)到达,因此:
code复制dp[i][j] = dp[i-1][j] + dp[i][j-1]
这个方程看似简单,但包含了动态规划的精髓——将大问题分解为子问题。我在初学时常犯的错误是忘记考虑边界条件,导致数组越界。
2.2.3 初始化技巧
初始化是动态规划容易出错的地方。我的经验是:
- 将dp[0][1]初始化为1(或dp[1][0])
- 其余边界位置保持为0
- 这样既保证了起点的正确性,又避免了复杂的边界判断
2.2.4 代码实现
cpp复制class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
dp[0][1] = 1;
