动态规划入门:从斐波那契到爬楼梯

一、动态规划核心思想

动态规划本质:拆分大问题为重叠子问题,保存子问题结果,避免重复计算

  • 适用场景:问题可拆解、子问题重复、存在最优子结构
  • 核心优势:把暴力递归指数级复杂度,优化为多项式复杂度
  • 两大关键点:状态定义状态转移方程

二、DP 解题标准四步(必按顺序分析)

  1. 状态定义 :定义 dp 数组含义,dp[i] 代表什么
  2. 初始状态:确定 dp 数组初始值、边界条件
  3. 状态转移:推导递推公式,建立前后状态关系
  4. 结果输出:确定最终答案对应 dp 数组位置

三、入门例题 1:斐波那契数列

题目描述

F(0) = 0,F(1) = 1F(n) = F(n-1) + F(n-2),求第 n 项数值。

1. 暴力递归(缺点:大量重复计算)

复制代码
int fib(int n)
{
    if(n == 0) return 0;
    if(n == 1) return 1;
    return fib(n-1) + fib(n-2);
}

2. 基础 DP 数组写法

复制代码
#include <iostream>
#include <vector>
using namespace std;

int fibDP(int n)
{
    if(n <= 1) return n;
    // 1. 状态定义:dp[i] 表示第i个斐波那契数
    vector<int> dp(n+1);
    // 2. 初始状态
    dp[0] = 0;
    dp[1] = 1;
    // 3. 状态转移方程
    for(int i = 2; i <= n; i++)
    {
        dp[i] = dp[i-1] + dp[i-2];
    }
    // 4. 输出结果
    return dp[n];
}

3. 空间优化版(滚动变量,O (1) 空间)

仅依赖前两个值,无需完整数组,刷题常用:

复制代码
int fibOpt(int n)
{
    if(n <= 1) return n;
    int a = 0, b = 1, c;
    for(int i = 2; i <= n; i++)
    {
        c = a + b;
        a = b;
        b = c;
    }
    return b;
}

四、入门例题 2:爬楼梯(LeetCode 70)

题目描述

每次只能爬 1 阶或 2 阶楼梯,求爬到第 n 阶共有多少种不同方法。

解题推导

  1. 状态定义dp[i] = 爬到第 i 阶楼梯的方法数
  2. 初始状态
    • dp 1 = 1(1 阶只有 1 种)
    • dp 2 = 2(2 阶:1+1 / 2)
  3. 状态转移 :到第 i 阶,只能从 i-1 或 i-2 过来 dp[i] = dp[i-1] + dp[i-2]

完整代码

复制代码
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];
}

空间优化版

复制代码
int climbStairsOpt(int n)
{
    if(n <= 2) return n;
    int pre1 = 1, pre2 = 2, cur;
    for(int i = 3; i <= n; i++)
    {
        cur = pre1 + pre2;
        pre1 = pre2;
        pre2 = cur;
    }
    return pre2;
}

五、DP 与递归、贪心简单区分

  1. 递归:自顶向下求解,重复计算多,效率低
  2. 动态规划:自底向上递推,缓存子问题结果,效率高
  3. 贪心:每一步选局部最优,不一定能得到全局最优;DP 一定求全局最优

六、动态规划常见分类

  1. 一维 DP:斐波那契、爬楼梯、打家劫舍(今日内容)
  2. 二维 DP:最长公共子序列、背包问题、路径问题
  3. 区间 DP、状态压缩 DP、树形 DP(进阶难点)

七、新手高频易错点

  1. 状态定义模糊,无法推导转移方程(DP 最大难点)
  2. 初始边界值设置错误,结果整体偏差
  3. 循环起止下标写错,漏算 / 重复计算
  4. 盲目套用模板,不分析题目状态关系

八、今日总结

  1. DP 核心:存子问题答案,避免重复计算
  2. 解题四步走:定义状态 → 初始化 → 状态转移 → 输出结果
  3. 斐波那契、爬楼梯是一维 DP 入门标杆,转移方程形式一致
  4. 可通过滚动变量优化空间,面试加分技巧
相关推荐
x_xbx9 小时前
LeetCode:739. 每日温度
算法·leetcode·职场和发展
不会C语言的男孩9 小时前
C++ Primer Plus 第3章:处理数据
开发语言·c++
RuiZN10 小时前
UE5 蓝图 FPS 02 Event Beginplay
c++·ue5
欧米欧10 小时前
C++进阶之AVL树
java·服务器·c++
艾莉丝努力练剑10 小时前
【Linux:文件】库的制作与原理进阶
linux·运维·服务器·网络·数据库·c++·人工智能
计算机安禾10 小时前
【算法分析与设计】第20篇:图论中的NP困难问题与近似策略
大数据·人工智能·算法
Trouvaille ~10 小时前
【优选算法篇】深入浅出链表算法:交换、重排与合并的终极策略
c++·算法·链表·面试·蓝桥杯·笔试·后端开发
Z_Wonderful10 小时前
大文件上传-分片上传-秒传
算法·哈希算法
heimeiyingwang10 小时前
【架构实战】分布式ID生成方案:雪花算法与业务ID设计
分布式·算法·架构