从小白开始的动态规划

一、动态规划的核心思想

动态规划(DP)通过拆分问题+记忆化计算解决复杂问题,核心步骤为:

  1. 定义状态 :用变量(如dp[i])表示子问题的解

  2. 状态转移方程:建立子问题之间的关系式

  3. 初始化:确定基础情况的初始值

  4. 计算顺序:确定填表方向(自底向上/自顶向下)

二、动态规划解题四部曲

  1. 分析问题是否具有重叠子问题最优子结构

  2. 定义明确的状态表示

  3. 推导状态转移关系

  4. 处理边界条件并实现


三、经典DP问题分类与实战

类型1:记忆化递归(斐波那契数列)

问题 :计算第n个斐波那契数
分析

  • 状态定义:dp[i]表示第i个斐波那契数

  • 转移方程:dp[i] = dp[i-1] + dp[i-2]

cpp 复制代码
int fib(int n) {
    if(n <= 1) return n;
    vector<int> dp(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];
}
类型2:线性DP(爬楼梯)

问题 :每次爬1/2阶,到n阶有多少种方法
分析

  • 状态定义:dp[i]表示到达第i阶的方法数

  • 转移方程:dp[i] = dp[i-1] + dp[i-2]

cpp 复制代码
int climbStairs(int n) {
    if(n <= 2) return n;
    vector<int> dp(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];
}
类型3:状态机DP(打家劫舍)

问题 :不能偷相邻房屋,求最大收益
分析

  • 状态定义:dp[i][0]不偷第i家的最大收益,dp[i][1]偷第i家的收益

  • 转移方程:
    dp[i][0] = max(dp[i-1][0], dp[i-1][1])
    dp[i][1] = dp[i-1][0] + nums[i]

cpp 复制代码
int rob(vector<int>& nums) {
    int n = nums.size();
    vector<vector<int>> dp(n, vector<int>(2));
    dp[0][0] = 0; dp[0][1] = nums[0];
    for(int i=1; i<n; ++i){
        dp[i][0] = max(dp[i-1][0], dp[i-1][1]);
        dp[i][1] = dp[i-1][0] + nums[i];
    }
    return max(dp[n-1][0], dp[n-1][1]);
}
类型4:背包问题(0-1背包)

问题 :容量W的背包,物品重量weight[]和价值value[],求最大价值
分析

  • 状态定义:dp[i][j]前i个物品装入容量j的背包的最大价值

  • 转移方程:
    dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i])

cpp 复制代码
int knapsack(int W, vector<int>& weight, vector<int>& value) {
    int n = weight.size();
    vector<vector<int>> dp(n+1, vector<int>(W+1));
    for(int i=1; i<=n; ++i){
        for(int j=1; j<=W; ++j){
            if(j >= weight[i-1]){
                dp[i][j] = max(dp[i-1][j], 
                             dp[i-1][j-weight[i-1]] + value[i-1]);
            }else{
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    return dp[n][W];
}
类型5:二维路径DP(最小路径和)

问题 :m x n网格,从左上到右下的最小路径和
分析

  • 状态定义:dp[i][j]表示到(i,j)的最小路径和

  • 转移方程:
    dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

cpp 复制代码
int minPathSum(vector<vector<int>>& grid) {
    int m = grid.size(), n = grid[0].size();
    vector<vector<int>> dp(m, vector<int>(n));
    dp[0][0] = grid[0][0];
    // 初始化第一列
    for(int i=1; i<m; ++i) dp[i][0] = dp[i-1][0] + grid[i][0];
    // 初始化第一行
    for(int j=1; j<n; ++j) dp[0][j] = dp[0][j-1] + grid[0][j];
    
    for(int i=1; i<m; ++i){
        for(int j=1; j<n; ++j){
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
        }
    }
    return dp[m-1][n-1];
}
类型6:字符串DP(编辑距离)

问题 :将word1转换为word2的最小操作次数(增/删/改)
分析

  • 状态定义:dp[i][j]表示word1前i个字符转成word2前j个字符的最小步数

  • 转移方程:

cpp 复制代码
if(word1[i-1] == word2[j-1]) 
    dp[i][j] = dp[i-1][j-1];
else
    dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;
cpp 复制代码
int minDistance(string word1, string word2) {
    int m = word1.size(), n = word2.size();
    vector<vector<int>> dp(m+1, vector<int>(n+1));
    for(int i=0; i<=m; ++i) dp[i][0] = i;
    for(int j=0; j<=n; ++j) dp[0][j] = j;
    
    for(int i=1; i<=m; ++i){
        for(int j=1; j<=n; ++j){
            if(word1[i-1] == word2[j-1]){
                dp[i][j] = dp[i-1][j-1];
            }else{
                dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;
            }
        }
    }
    return dp[m][n];
}

四、动态规划的优化技巧

  1. 状态压缩:二维转一维(如背包问题使用滚动数组)

  2. 空间优化:复用数组空间

  3. 记忆化搜索:递归+备忘录的写法


五、如何有效练习DP

  1. 从经典模板题入手(斐波那契、背包、路径问题)

  2. 先尝试自己推导状态转移方程

  3. 对比他人解法优化空间复杂度

  4. 逐步挑战Hard题目(最长递增子序列、股票买卖问题等)

动态规划就像搭积木------找到正确的子问题拆分方式,建立状态间的联系,通过不断练习积累"问题模式"的识别能力。坚持每天解决一个DP问题,你会在两个月后发现自己质的飞跃!

相关推荐
王老师青少年编程4 分钟前
【如何掌握CSP-J 信奥赛中的排序算法】
c++·算法·排序算法·csp·信奥赛
爱是小小的癌4 分钟前
数据结构与算法之排序算法-快速排序(分治)
java·开发语言·数据结构·算法·排序算法
✿ ༺ ོIT技术༻12 分钟前
剑指offer第2版:搜索算法(二分/DFS/BFS)
数据结构·算法
金融OG17 分钟前
100.13 AI量化面试题:支持向量机(SVM)如何处理高维和复杂数据集?
人工智能·python·算法·机器学习·支持向量机·数学建模·金融
技术小泽30 分钟前
算法基础之排序算法大总结1!!
java·数据结构·后端·算法·排序算法
云卓SKYDROID1 小时前
无人机之无线传输技术!
科技·算法·无人机·科普·云卓科技
蓝色洛特1 小时前
【matlab优化算法-17期】基于DBO算法的微电网多目标优化调度
开发语言·算法·matlab
豆豆酱2 小时前
强化学习到大模型训练理论概要(三)
算法
Strive_Sun2 小时前
Windows 下搭建 googletest 测试框架(C/C++)
c语言·开发语言·c++·windows
小禾苗_2 小时前
C++ ——基础进阶
开发语言·c++