动态规划算法:

动态规划算法简介

动态规划(Dynamic Programming, DP)是一种将复杂问题分解为更简单的子问题来求解的算法思想。它通过保存中间子问题的解,避免了重复计算,从而大大提高了解决问题的效率。动态规划通常用于求解最优化问题,比如最短路径、最大收益等。

动态规划解题步骤
  1. 确定状态:明确在问题的某一步中,需要存储什么信息来描述子问题的解。
  2. 状态转移方程:找出如何通过前一步的状态来得到当前状态,即如何递推地求解问题。
  3. 初始状态:确定最基本的状态,即最小子问题的解。
  4. 计算结果:通过状态转移逐步得到问题的最终解。

递归与动态规划的对比

为了更好地理解动态规划的优势,我们以“爬楼梯”问题为例,展示递归方法与动态规划方法的对比。

1. 爬楼梯问题(一维)

假设你正在爬楼梯,需要爬 n 阶才能到达楼顶。每次你可以爬 12 个台阶。问有多少种不同的方法可以爬到楼顶?

递归解法:

class Solution {
public:
    int climbStairs(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
        if(n == 2) return 2;
        return climbStairs(n - 1) + climbStairs(n - 2);
    }
};

递归方法虽然直观,但由于存在大量重复计算,导致时间复杂度较高(O(2^n)),在 n 较大时会超时。

动态规划解法:

class Solution {
public:
    int climbStairs(int n) {
        vector dp(n+1);
        if(n <= 1) return 1;
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i <= n; i++) {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
};

动态规划方法通过自底向上地保存子问题的解,避免了递归中的重复计算。其时间复杂度为 O(n),空间复杂度也可以进一步优化到 O(1)

机器人走路问题(二维)

题目描述:

一个机器人位于一个 m x n 网格的左上角(起始点标记为“Start”)。机器人每次只能向下或者向右移动一步,目标是达到网格的右下角(标记为“Finish”)。问总共有多少条不同的路径?

动态规划解法:

解题思路:

  • 状态定义:定义一个二维数组 dp[i][j],表示机器人从左上角走到 (i, j) 的不同路径数。
  • 状态转移方程:对于每个格子 (i, j),机器人可以从上方 (i-1, j) 或左方 (i, j-1) 到达,因此 dp[i][j] = dp[i-1][j] + dp[i][j-1]
  • 初始状态:在边界上,机器人只能从一个方向到达,因此 dp[i][1] = 1dp[1][j] = 1
  • 最终结果:目标是求解右下角 dp[m][n]

代码实现:

class Solution {
public:
    int uniquePaths(int m, int n) {
        int dp[m+1][n+1];
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if(i == 1 || j == 1) {
                    dp[i][j] = 1;
                } else {
                    dp[i][j] = dp[i][j-1] + dp[i-1][j];
                }
            }
        }
        return dp[m][n];
    }
};

代码解读:
  1. 二维DP数组dp[m+1][n+1] 用于存储从起点到各个位置的路径数目。
  2. 边界条件:因为机器人只能向右或向下移动,因此边界上的路径数目为 1
  3. 状态转移方程:对于非边界点,路径数目等于上方和左方路径数目的和。
  4. 时间复杂度与空间复杂度:该算法的时间复杂度为 O(m * n),可以通过仅使用一维数组优化空间复杂度到 O(min(m, n))

结论

通过这两个经典问题的分析,我们看到动态规划方法在处理复杂问题时的强大之处。相比于递归,动态规划通过存储子问题的解,有效减少了重复计算,显著提升了算法的效率。因此,在面临类似的问题时,动态规划通常是更为优越的选择。

你可能感兴趣的:(算法,动态规划)