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

动态规划解斐波那契问题:三步、爬楼梯与解码方法

通过泰波那契数、三步问题、最小花费爬楼梯和解码方法四道 LeetCode 题目,演示了动态规划中斐波那契递推模型的解题套路,包括状态定义、转移方程、初始化细节和空间优化技巧。

栈溢出发布于 2026/6/15更新于 2026/10/1873 浏览
动态规划解斐波那契问题:三步、爬楼梯与解码方法

动态规划的核心,无非是定义状态、找到转移,再按顺序填表。很多问题都能套进一个类似斐波那契的递推结构中,比如泰波那契、爬楼梯、解码方法——它们都在dp[i]依赖于前几项的值,只是依赖的规则略有不同。

下面用四道 LeetCode 题目,看一下这个模型的几处变形。

第 N 个泰波那契数(LeetCode 1137)

题目要求:T0 = 0, T1 = 1, T2 = 1,且 Tn = Tn-1 + Tn-2 + Tn-3(n >= 3)。返回 Tn。

文章配图

状态表示很直接:dp[i] 即第 i 个泰波那契数。转移方程即为dp[i] = dp[i-1] + dp[i-2] + dp[i-3]。初始化前三个值,然后从左往右填即可。

// 时间复杂度:O(N)
// 空间复杂度:O(N)
class Solution {
    public int tribonacci(int n) {
        if (n < 3) return n == 0 ? 0 : 1;
        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;
        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 阶有多少种走法。

文章配图

这跟泰波那契几乎一致,只是初始值略有不同。设 dp[i] 表示走到第 i 阶的方法数,则 dp[i] = dp[i-1] + dp[i-2] + dp[i-3]。当 i=0 时,只有一种方式(原地不动);i=1 时只有一种;i=2 时可以一步到顶或者分两步,共两种。因此初始化 dp[0]=1, dp[1]=1, dp[2]=2。注意题目要求结果对 1000000007 取模,因此在累加时就要取模,避免溢出。

// 时间复杂度:O(N)
// 空间复杂度:O(N)
class Solution {
    public int waysToStep(int n) {
        if (n < 3) return n;
        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];
    }
}

使用最小花费爬楼梯(LeetCode 746)

这题不再是求方案数,而是求最小花费。给一个 cost 数组,cost[i] 表示从第 i 阶往上走需要支付的费用;可以从第0或第1阶开始,目标是到达楼顶(下标为 n,n = cost.length)。每次可以爬1或2阶。

这次 dp[i] 定义为到达第 i 阶的最小累计花费。那么到达 i 阶可以从 i-1 阶走一步,花费 dp[i-1] + cost[i-1],或者从 i-2 阶走两步,花费 dp[i-2] + cost[i-2]。两者取最小。初始化时,从起点出发,dp[0]=0, dp[1]=0(因为可以选择从第0阶或第1阶开始,所以到达第0阶和第1阶本身不花费)。填表顺序从左到右,最后返回 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];
    }
}

解码方法(LeetCode 91)

这道题稍微复杂一些,但状态转移依然只依赖于前两项。给出一个只含数字的字符串,编码规则是 126 分别对应字母 AZ,问有多少种不同的解码方式。

文章配图

定义 dp[i] 为字符串前 i+1 个字符(索引 0..i)的解码方法数。对于当前位置 i,字符 s[i] 如果为 '1''9',就可以单独解码,此时方案数加上 dp[i-1];如果 s[i-1] 和 s[i] 组成的两位数在 1026 之间,则可以整体解码为一个字母,方案数再加上 dp[i-2]。初始化时要注意 '0' 开头的字符串直接返回 0。第一个位置单独判断,第二个位置同时判断单个和组合情况。

class Solution {
    public int numDecodings(String s) {
        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];
    }
}

这几道题都是线性 DP 里非常典型的「斐波那契式递推」问题。只要你把状态定义清楚,初始化填对,剩下的就是一路填表而已。空间优化可以滚动数组,但一般先写出完整的 dp 数组再优化会更不容易出错。

目录

  1. 第 N 个泰波那契数(LeetCode 1137)
  2. 三步问题(面试题 08.01)
  3. 使用最小花费爬楼梯(LeetCode 746)
  4. 解码方法(LeetCode 91)

更多推荐文章

查看全部
  • 前端监控:别等用户告诉你应用崩了
  • OpenClaw 对接 Stable Diffusion 教程
  • Python 驱动的 ADS 自动化仿真框架与 API 实战指南
  • Cursor Composer Agent 详解:多 Agent 协作完成复杂项目
  • OpenClaw QQ 机器人接入实战指南
  • 二分查找经典例题解析与模板总结
  • Visual C++ Redistributable 运行库安装与 DLL 缺失修复指南
  • Open-AutoGLM 开源模型下载与本地运行配置
  • 星辰 RPA 搭建小红书自动发文机器人
  • Mac 系统部署 OpenClaw 本地 AI 自动化框架指南
  • 如何挖掘大模型应用场景及驱动技术发展
  • GPT-OSS-20B 多用户并发 WEBUI 压力测试
  • 基于 IDEA 搭建 Spring Boot + MyBatis + MySQL 工程实践
  • 生成式 AI 落地现状:19 个场景、26 个行业与 106 个案例深度分析
  • Python 爬虫实战:爬取今日头条图文标题
  • Python 最常用的 10 个内置函数详解
  • Discord 机器人创建与配置完整流程
  • 从零开始:如何使用 Python 训练 AI 模型
  • Spring Data JPA 原理与实战:Repository 接口机制详解
  • 大模型落地路线图研究报告(2024)

相关免费在线工具

  • 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