【算法篇】清晰易懂掌握动态规划

动态规划:用“记住过去”解决复杂问题的智慧

动态规划(Dynamic Programming,DP)是一种通过记录子问题解来避免重复计算的算法思想。如果说贪心算法是“只看眼前最优”,那么动态规划就是“记住过去每一步的选择”。本文将通过生活化的例子和Java代码实现,带你轻松理解动态规划的精髓!


一、什么是动态规划?

动态规划的核心思想是:将大问题分解为小问题,通过保存小问题的解来避免重复计算。就像我们解数学题时先记住公式,下次遇到相同问题直接使用结果。

举个生活中的例子 🧩

假设你要爬10级台阶,每次可以爬1级或2级。问有多少种不同的方法?
如果用暴力递归会重复计算很多子问题(比如爬第8级台阶的方法会被反复计算)。而动态规划会用一个表格记录每一级台阶的方法数,后续直接查表。


二、动态规划的适用条件

动态规划需要满足两个关键条件:

  1. 最优子结构:大问题的最优解包含子问题的最优解
  2. 重叠子问题:子问题会被重复计算多次

⚠️ 注意:动态规划常用于解决贪心算法无法处理的复杂优化问题(如0-1背包问题)。


三、经典案例:硬币找零问题

问题描述

给定不同面额的硬币(如1元、3元、5元)和一个总金额(如11元),求组成该金额的最少硬币数
(若面额为1、3、5时,贪心算法会失效:比如找9元,贪心选5+1+1+1=4枚,实际最优是3+3+3=3枚)

动态规划策略

  1. 定义dp数组:dp[i]表示金额i的最小硬币数
  2. 初始状态:dp[0] = 0
  3. 状态转移方程:dp[i] = min(dp[i-coin] + 1)(对所有硬币面额)

Java代码实现

public class DpExample {
    public static void main(String[] args) {
        int[] coins = {1, 3, 5};
        int amount = 11;
        int[] dp = new int[amount+1];
        Arrays.fill(dp, amount+1); // 初始化为极大值
        dp[0] = 0;

        for (int i = 1; i <= amount; i++) {
            for (int coin : coins) {
                if (coin <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                }
            }
        }

        System.out.println("最少需要硬币数: " + 
            (dp[amount] > amount ? -1 : dp[amount]));
    }
}

输出结果

最少需要硬币数: 3  // 5+5+1(或3+3+5)

四、如何识别适用动态规划的问题?

遇到以下特征时,可以考虑动态规划:

  1. 问题可以分解为相似的子问题
  2. 子问题会被重复计算
  3. 常见应用场景:背包问题、最长公共子序列、编辑距离、股票买卖问题等

五、动态规划的两种实现方式

1. 自顶向下(记忆化搜索)

用递归实现,用哈希表缓存结果
适合子问题数量较少的情况

2. 自底向上(迭代填表)

用循环实现,显式构建dp表
适合需要优化空间复杂度的情况


六、动态规划的优缺点

优点

  • 能保证得到全局最优解
  • 通过存储中间结果大幅提升效率

缺点

  • 需要额外存储空间
  • 对无重叠子问题的问题反而降低效率

七、总结

动态规划像一本精心记录的笔记本:

  1. 拆解问题:将大象放进冰箱分三步
  2. 记住结果:避免重复造轮子
  3. 组合答案:用小问题的解构建大问题的解

下次遇到复杂问题时,尝试问自己:
“这个问题能否拆解成子问题?子问题是否会被重复计算?”
如果答案是肯定的,动态规划就是你需要的利器! 🔨


扩展思考
尝试用动态规划解决「青蛙过河」问题(LeetCode 403),体会状态转移的设计技巧。对比暴力递归与动态规划的时间复杂度差异,感受DP的威力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tee xm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值