跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

动态规划经典模型:斐波那契数列及变体

动态规划解题模版包含状态表示、转移方程、初始化、填表顺序及返回值五个要素。文章通过第 N 个泰波那契数、三步问题、最小花费爬楼梯和解码方法四个实例,演示了斐波那契类问题的状态定义与转移逻辑。提供 Java 代码实现,并针对前两个问题展示了空间复杂度从 O(N) 到 O(1) 的优化方案。

kaikai发布于 2026/3/23更新于 2026/7/630 浏览
动态规划经典模型:斐波那契数列及变体

一、动态规划解题模版

  1. 状态表示:一般创建一个一维数组 dp,把 dp 表填满,其中的某一个值就是结果。状态表示指 dp 表中元素的含义。
    • 来源:题目要求、经验 + 题目要求,分析问题的过程中的重复子问题
  2. 状态转移方程:dp[i] = ?
  3. 初始化:保证根据状态转移方程填表时不越界
  4. 填表顺序:为了填写当前状态的时候,所需要的状态已经计算过了
  5. 返回值:题目要求 + 状态表示

二、第 N 个泰波那契数

题目描述:第四个数是前三个数的和,第一二三个数定为 0 1 1,返回第 n 个数。

文章配图

题目解析:

解题思路:

  1. 状态表示:dp[i] 表示第 i 个泰波那契数
  2. 状态转移方程:dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
  3. 初始化:dp[0] = 0, dp[1] = 1, dp[2] = 1
  4. 填表顺序:顺序从左向右填表即可
  5. 返回值:dp[n]

解题代码:

// 时间复杂度:O(N) // 空间复杂度:O(N)
class Solution {
    public int tribonacci(int n) {
        if (n < 3) return n == 0 ? 0 : 1;
        // 创建 dp 表
        int[] dp = new int[n + 1];
        // 初始化
        dp[0] = 0; dp[1] = dp[2] = 1;
        // 填表
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
        }
        // 返回值
        return dp[n];
    }
}

空间优化:只创建长度为三的数组即可:

// 时间复杂度:O(N) // 空间复杂度:O(1)
class Solution {
    public int tribonacci(int n) {
        if (n < 3) return n == 0 ? 0 : 1;
        // 创建 dp 表
        int[] dp = new int[]{0, 1, 1};
        // 填表
        for (int i = 3; i <= n; i++) {
            int tmp = dp[0];
            dp[0] = dp[1];
            dp[1] = dp[2];
            dp[2] = tmp + dp[0] + dp[1];
        }
        // 返回值
        return dp[2];
    }
}

三、面试题 08.01. 三步问题

题目描述:

文章配图

题目解析:

  • 每一次上楼梯有三个选择:1, 2, 3,返回走到第 n 阶梯有多少种走法

解题思路:

  1. 状态表示:dp[i] 表示第 i 阶的上楼方式种类数
  2. 状态转移方程:dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
  3. 初始化:dp[0] = 1, dp[1] = 1, dp[2] = 2(小孩有 3 种走法,那么小孩的上一个台阶的可能就是 i-1, i-2, i-3)
  4. 填表顺序:顺序从左向右填表即可
  5. 返回值:dp[n]

解题代码:

// 时间复杂度:O(N) // 空间复杂度:O(N)
class Solution {
    public int waysToStep(int n) {
        if (n < 3) return n;
        // 建立 dp 表
        int[] dp = new int[n + 1];
        // 初始化
        dp[0] = dp[1] = 1; dp[2] = 2;
        // 填表
        for (int i = 3; i <= n; i++) {
            dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;
        }
        // 返回值
        return dp[n];
    }
}

四、746. 使用最小花费爬楼梯(easy)

题目描述:

题目解析:

  • 给我们一个 cost 数组,表示走出这一个台阶需要的花费
  • 可以选择第一步从 cost[0] 还是 cost[1] 开始
  • 让我们返回到达楼顶的最小总花费

解题思路:

  1. 状态表示:dp[i] 表示走到第 i 阶的最小花费
  2. 状态转移方程:dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
  3. 初始化:表的长度要比 cost 大 1,表示楼顶
  4. 填表顺序:顺序从左向右填表即可
  5. 返回值:dp[n]

解题代码:

// 时间复杂度:O(N) // 空间复杂度:O(N)
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int n = cost.length;
        if (n == 2) return Math.min(cost[0], cost[1]);
        // 状态转移表
        int[] dp = new int[n + 1];
        // 状态转移方程
        for (int i = 2; i <= n; i++) {
            dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
        }
        return dp[n];
    }
}

五、91.解码方法

题目描述:

文章配图

题目解析:

  • 给我们一个编码规则,数字 1 - 26 对应表示字母 A - Z
  • 给我们一个纯数字的字符串,让我们将字符串进行拆分,拆分后的字符串,对应的所有子串都可以对应表示成字母
  • 求可以拆分的种数

解题思路:

  1. 状态表示:dp[i] 表示字符串中 0 到 i 字符的合法拆分结果
  2. 状态转移方程:
    • i 位置上字符为 1 到 9 的字符单独解码成功 dp[i] += dp[i - 1]
    • i 与 i-1 位置上的字符组合是 10 到 26 的合法编码 dp[i] += dp[i - 2]
  3. 初始化:
    • dp[0]:第一个字符不为 0,就 dp[0] = 1,为 0 就返回 0
    • dp[1]:该字符不为 0,dp[1] += dp[0],与第 0 个字符组成合法编码 10 - 26,dp[1] += 1

填表顺序:从左到右 返回值:dp[n - 1]

解题代码:

class Solution {
    public int numDecodings(String s) {
        // 前导 0
        if (s.charAt(0) == '0') return 0;
        int n = s.length();
        char[] ch = s.toCharArray();
        // 只有一个字符
        if (n == 1) return 1;
        int[] dp = new int[n];
        // 初始化
        dp[0] = 1;
        // 初始化第二个元素
        if (ch[1] != '0' && ch[0] != '0') dp[1] += 1;
        int t = (ch[1] - '0') + (ch[0] - '0') * 10;
        if (t >= 10 && t <= 26) dp[1] += 1;
        // 填表
        for (int i = 2; i < n; i++) {
            // 该字符单独组
            if (ch[i] != '0') dp[i] += dp[i - 1];
            // 与前一个字符组
            t = (ch[i] - '0') + (ch[i - 1] - '0') * 10;
            if (t >= 10 && t <= 26) dp[i] += dp[i - 2];
        }
        return dp[n - 1];
    }
}

目录

  1. 一、动态规划解题模版
  2. 二、第 N 个泰波那契数
  3. 三、面试题 08.01. 三步问题
  4. 四、746. 使用最小花费爬楼梯(easy)
  5. 五、91.解码方法
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • VSCode 通过 SSH 远程连接 Ubuntu 配置指南
  • OpenClaw 在 Linux 环境下的安装、初始化及 Web UI 配置
  • C++ 多线程同步:原子操作 atomic 实战
  • C++ 类与对象:封装特性实现与实战详解
  • 大模型驱动的数字员工3.0建设应用白皮书核心解读
  • Python 合并多个 PDF 文件:完整指南与实践
  • 人形运控部署框架汇总:rsl_rl 与 unitree_rl_gym 解析
  • 前缀和算法实战:从一维到二维及哈希结合应用
  • ROS2 功能包创建与 CMake 编译链路详解
  • Python 在 CentOS 系统上的安装与配置深度指南
  • AI 辅助 imToken 生态开发:智能合约交互与监控脚本生成实践
  • Ollama 模型管理与删除及 Open WebUI 部署
  • GitHub 启用双因素身份验证(2FA)配置指南
  • Whisper 与 Faster-Whisper 模型下载、安装及运行指南
  • C++ Qt 窗口框架与菜单栏 QMenuBar 详解
  • jQuery 前端开发核心指南:语法、DOM 操作及 Validate 插件
  • 使用文心一言为智能体设计稳定调用工作流的提示词
  • MySQL 安装后出现无法连接远程主机 catalog 下载失败错误解决
  • 程序员为何越努力越焦虑:突破认知困境与构建知识体系
  • 基于 Canvas 和 Web Audio API 的交互式烟花动画实现

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online