动态规划(DP)从入门到精通:原理详解与经典问题解析

动态规划(DP)从入门到精通:原理详解与经典问题解析

1. 引言

动态规划(Dynamic Programming,简称DP)是算法设计与优化中的一种重要方法,广泛应用于计算机科学、人工智能、运筹学等领域。许多经典问题,如背包问题、最短路径问题、编辑距离等,都可以通过动态规划高效解决。

本文将系统介绍动态规划的核心思想、解题步骤,并通过多个经典案例(附Java代码实现)帮助读者掌握动态规划的解题技巧。


2. 动态规划的核心思想

动态规划适用于具有以下两个性质的问题:

  1. 重叠子问题(Overlapping Subproblems)

    问题可以被分解为多个相似的子问题,且子问题会被重复计算。
    示例 :斐波那契数列 F(n) = F(n-1) + F(n-2),其中 F(3) 可能被 F(4)F(5) 多次计算。

  2. 最优子结构(Optimal Substructure)

    问题的最优解可以由其子问题的最优解推导而来。
    示例:最短路径问题中,A→C 的最短路径 = A→B 的最短路径 + B→C 的最短路径。

动态规划通过**记忆化存储(Memoization)填表法(Tabulation)**避免重复计算,提高效率。


3. 动态规划的解题步骤

步骤1:定义状态

  • 明确 dp[i]dp[i][j] 表示的含义。
  • 示例 :在斐波那契数列中,dp[i] 表示第 i 个斐波那契数。

步骤2:状态转移方程

  • 找出 dp[i]dp[i-1]dp[i-2] 等子问题的关系。
  • 示例dp[i] = dp[i-1] + dp[i-2](斐波那契数列)。

步骤3:初始化

  • 设置初始条件,如 dp[0]dp[1] 的值。
  • 示例dp[0] = 0, dp[1] = 1(斐波那契数列)。

步骤4:计算顺序

  • 确定填表顺序(通常自底向上)。
  • 示例 :计算 dp[2]dp[3] → ... → dp[n]

步骤5:返回结果

  • dp 表中提取最终答案。
  • 示例return dp[n](斐波那契数列)。

4. 经典动态规划问题

问题1:斐波那契数列(LeetCode 509)

问题描述 :计算第 n 个斐波那契数(F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2))。

Java实现
java 复制代码
public int fib(int n) {
    if (n <= 1) return n;
    int[] dp = new int[n + 1];
    dp[0] = 0;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

// 空间优化版(O(1)空间)
public int fibOptimized(int n) {
    if (n <= 1) return n;
    int prev1 = 1, prev2 = 0;
    for (int i = 2; i <= n; i++) {
        int curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

问题2:爬楼梯(LeetCode 70)

问题描述 :每次可以爬1或2阶台阶,求爬到第 n 阶有多少种方法。

状态转移方程

dp[i] = dp[i-1] + dp[i-2](类似斐波那契数列)

Java实现
java 复制代码
public int climbStairs(int n) {
    if (n <= 2) return n;
    int[] dp = new int[n + 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];
}

// 空间优化版
public int climbStairsOptimized(int n) {
    if (n <= 2) return n;
    int prev1 = 2, prev2 = 1;
    for (int i = 3; i <= n; i++) {
        int curr = prev1 + prev2;
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1;
}

问题3:0-1背包问题

问题描述 :给定物品重量 weights 和价值 values,背包容量 W,求能装入的最大价值(每个物品只能选或不选)。

状态转移方程
css 复制代码
dp[i][w] = max(dp[i-1][w], values[i] + dp[i-1][w - weights[i]])
Java实现
java 复制代码
public int knapsack(int W, int[] weights, int[] values) {
    int n = weights.length;
    int[][] dp = new int[n + 1][W + 1];
    
    for (int i = 1; i <= n; i++) {
        for (int w = 1; w <= W; w++) {
            if (weights[i - 1] <= w) {
                dp[i][w] = Math.max(
                    dp[i - 1][w], 
                    values[i - 1] + dp[i - 1][w - weights[i - 1]]
                );
            } else {
                dp[i][w] = dp[i - 1][w];
            }
        }
    }
    return dp[n][W];
}

// 空间优化版(一维数组)
public int knapsackOptimized(int W, int[] weights, int[] values) {
    int[] dp = new int[W + 1];
    
    for (int i = 0; i < weights.length; i++) {
        for (int w = W; w >= weights[i]; w--) {
            dp[w] = Math.max(dp[w], values[i] + dp[w - weights[i]]);
        }
    }
    return dp[W];
}

5. 动态规划的优化技巧

  1. 空间优化

    • 很多二维DP可以优化为一维(如背包问题)。
  2. 状态压缩

    • 用位运算表示状态(如旅行商问题TSP)。
  3. 记忆化搜索(Memoization)

    • 自顶向下递归+缓存,避免重复计算。
  4. 滚动数组

    • 只保留必要的状态(如斐波那契数列只需 prev1prev2)。

6. 总结

动态规划是算法竞赛和面试中的高频考点,掌握其核心思想和经典问题解法至关重要。建议:

  1. 从简单问题入手(斐波那契、爬楼梯)。
  2. 理解状态转移方程的推导过程。
  3. 多练习LeetCode上的DP专题(如LIS、编辑距离、股票买卖问题)。
  4. 尝试优化空间复杂度。

希望本文能帮助你系统掌握动态规划!欢迎在评论区交流讨论。🚀

相关推荐
程序员阿鹏3 分钟前
为什么MySQL InnoDB选择B+树?
数据结构·数据库·b树·sql·mysql·算法·缓存
AI 思录25 分钟前
Prompt 事故档案(八):日常表达被标为“待校准”,AI 的爹味语法从哪里来
大数据·人工智能·算法·prompt·用户体验·ai合规
月光船幽幽30 分钟前
跨范式映射的稳定接口设计
人工智能·python·算法
信誓旦旦的程序猿42 分钟前
【量化系统从零构建 #04】存储设计:选型·建库·交易日历
java·人工智能·python·股票数据api·股票数据·股票数据api接口·股票api数据接口
yurenpai(27届找实习中)42 分钟前
Java 10 的 var 为什么不能随便用?从订单汇总看懂类型推断与泛型陷阱
java·开发语言·java18
Flynt2 小时前
把公司项目迁到 Spring Boot 4.0:编译通过只是开始
java·spring boot·后端
2601_965742222 小时前
全媒体运营与短视频代运营,两者有什么区别?
大数据·数据结构·人工智能·算法·ai·媒体
Tangyuewei2 小时前
给老 Spring 项目装个 AI Agent
java·人工智能·spring
她的男孩2 小时前
多租户和数据权限怎么共存?扒完拦截器注册链路,我找到 4 个隐蔽的坑
java·后端·架构
wordbaby3 小时前
混合检索:两全其美的艺术
人工智能·算法