蓝桥杯 Java B 组之简单动态规划(爬楼梯、斐波那契数列)

news2025/3/14 13:18:13

Day 6:简单动态规划(爬楼梯、斐波那契数列)

动态规划(Dynamic Programming,简称 DP)是计算机科学中的一种算法设计思想,用来解决最优解问题,它的核心思想是将大问题分解为小问题,并通过保存计算结果避免重复计算。常见的应用场景包括:最短路径、最优子结构、背包问题等。

今天,我们将详细学习两个经典的动态规划问题:

  • 爬楼梯问题
  • 斐波那契数列

 一、动态规划概念

动态规划适用于能够分解为子问题的问题,并且子问题的解可以保存并复用。动态规划通过状态转移方程来计算最优解。

通俗理解:动态规划就像“做笔记”——把重复计算的结果记录下来,避免重复劳动。

核心思想:将大问题拆解为小问题,通过解决小问题逐步解决大问题,并保存中间结果(称为“状态”)。

1. 状态转移方程
  • 状态转移方程是用来描述从一个状态另一个状态的关系。
  • 通过状态转移方程,可以一步步得到最终的最优解。


 二、爬楼梯问题

问题描述:

假设你正在爬楼梯,楼梯有 n 阶,每次可以爬 1 阶或 2 阶。你有多少种方法可以爬到楼顶?

思路分析:
  • 对于楼梯的第 n 阶,你可以从第 n-1 阶跳一步,或者从第 n-2 阶跳两步。
  • 所以,到达第 n 阶的方法数等于到达第 n-1 阶和第 n-2 阶的方法数之和。
状态转移方程:

f(n)=f(n−1)+f(n−2)f(n) = f(n-1) + f(n-2)

  • f(n) 表示到达第 n 阶的总方法数。
  • 初始条件:
    • f(0) = 1(没有阶梯时有一种“爬”的方法,就是不动)
    • f(1) = 1(只有一阶时,只有一种爬法)
代码实现:
public class ClimbingStairs {

    public static int climbStairs(int n) {

        if (n == 0) return 0;  // 没有楼梯的情况

        if (n == 1) return 1;  // 只有一阶的情况



        int first = 1;  // f(1) = 1

        int second = 2; // f(2) = 2

        int result = 0;



        for (int i = 3; i <= n; i++) {

            result = first + second;  // f(n) = f(n-1) + f(n-2)

            first = second;           // 更新 f(n-1)

            second = result;          // 更新 f(n-2)

        }

        return result;

    }



    public static void main(String[] args) {

        int n = 5;  // 假设楼梯有 5 阶

        System.out.println(climbStairs(n));  // 输出结果

    }

}
  • 解释
    • 初始化 first = 1 和 second = 2,分别表示到达第 1 阶和第 2 阶的方法数。
    • 通过循环从第 3 阶开始,根据状态转移方程 f(n) = f(n-1) + f(n-2) 计算到达每一阶的方法数,最终返回到达第 n 阶的总方法数。
时间复杂度: O(n)
空间复杂度: O(1)

这个解法通过空间优化,只用常数空间来存储前两个状态,因此是最优解。


 三、斐波那契数列(Fibonacci Sequence)

问题描述:

斐波那契数列是一个经典的数列,定义如下:

f(0)=0f(1)=1f(n)=f(n−1)+f(n−2),n>=2f(0) = 0 f(1) = 1 f(n) = f(n-1) + f(n-2), n >= 2

即数列的前两个数字是 0 和 1,从第三项开始,每一项是前两项之和。计算第 n 项。

思路分析:
  • 斐波那契数列和爬楼梯问题是同一种类型的问题。
  • 第 n 项的数值是前两项之和,符合动态规划的最优子结构
状态转移方程:

f(n)=f(n−1)+f(n−2)f(n) = f(n-1) + f(n-2)

代码实现(递归):
public class Fibonacci {

    // 递归实现

    public static int fib(int n) {

        if (n == 0) return 0;

        if (n == 1) return 1;

        return fib(n - 1) + fib(n - 2);  // 递归调用

    }



    public static void main(String[] args) {

        int n = 6;  // 求斐波那契数列的第 6 项

        System.out.println(fib(n));  // 输出结果

    }

}
  • 解释: 
    • 基本的递归实现,计算第 n 项的数值。
    • 递归的时间复杂度是 O(2^n),因为每个递归会产生两个子问题,计算速度较慢。
改进:动态规划实现(记忆化递归)
public class FibonacciDP {

    public static int fib(int n) {

        int[] dp = new int[n + 1];

        dp[0] = 0;  // f(0) = 0

        dp[1] = 1;  // f(1) = 1



        for (int i = 2; i <= n; i++) {

            dp[i] = dp[i - 1] + dp[i - 2];  // 状态转移方程

        }



        return dp[n];

    }



    public static void main(String[] args) {

        int n = 6;  // 求斐波那契数列的第 6 项

        System.out.println(fib(n));  // 输出结果

    }

}
  • 解释: 
    • 使用 动态规划 数组 dp 来存储中间结果,避免重复计算。
    • 时间复杂度是 O(n),空间复杂度是 O(n)。
    • 为什么使用n + 1:
    • 索引从0开始:在Java中,数组的索引是从0开始的。因此,如果我们想要存储从第1项到第n项的解,我们需要一个长度为n + 1的数组,这样索引范围就是从0到n。
    • 方便访问:使用n + 1的数组,我们可以直接使用dp[i]来访问第i项的解,而不需要进行额外的索引转换。
优化:空间复杂度 O(1)
public class FibonacciOptimized {

    public static int fib(int n) {

        if (n == 0) return 0;

        if (n == 1) return 1;



        int first = 0, second = 1;  // f(0) = 0, f(1) = 1

        int result = 0;



        for (int i = 2; i <= n; i++) {

            result = first + second;

            first = second;

            second = result;

        }



        return result;

    }



    public static void main(String[] args) {

        int n = 6;  // 求斐波那契数列的第 6 项

        System.out.println(fib(n));  // 输出结果

    }

}
  • 解释: 
    • 通过空间优化,只用两个变量 first 和 second 存储前两个斐波那契数值,减少了空间复杂度。
    • 时间复杂度是 O(n),空间复杂度是 O(1)。
总结:
  • 递归法: 直接递归实现,虽然简单,但由于大量重复计算,效率低。
  • 动态规划(DP): 通过存储中间计算结果,避免重复计算,显著提高效率。
  • 空间优化: 动态规划可以通过滚动数组技巧来优化空间复杂度。
时间复杂度: O(n)
空间复杂度: O(1)(优化后的解法)


四、常考点总结

知识点

内容

常见问题

状态转移方程

动态规划的核心是递推关系(例如:f(n) = f(n-1) + f(n-2))

题目能否用动态规划解决,是否存在最优子结构?

爬楼梯问题

动态规划解法,关键是通过状态转移方程f(n) = f(n-1) + f(n-2)来计算

边界条件的处理,空间优化的使用

**斐波那契

动态规划解题步骤总结

定义状态:明确dp[i]表示什么(如斐波那契数、爬楼梯方法数)。

建立状态转移方程:找到dp[i]与dp[i-1]、dp[i-2]等的关系。

初始化:设置初始值(如dp[0]、dp[1])。

确定计算顺序:通常从前往后遍历。

空间优化:用变量代替数组(如滚动数组)。

常考题型

基础DP问题:斐波那契、爬楼梯、路径计数。

变种DP问题:最小路径和、背包问题简化版。

二维DP问题:网格中的动态规划(如机器人路径)。

动态规划的两个主要特征:

重叠子问题:问题可以分解为多个子问题,这些子问题不是独立的,而是相互重叠的。

最优子结构:问题的最优解包含其子问题的最优解。

爬楼梯问题

爬楼梯问题是一个经典的动态规划问题。假设你正在爬楼梯,每次可以爬1阶或2阶,问到达第n阶楼梯有多少种不同的方法。

解题思路:

状态定义:设dp[i]表示到达第i阶楼梯的方法数。

状态转移方程:dp[i] = dp[i-1] + dp[i-2],即到达第i阶的方法数等于到达第i-1阶和第i-2阶的方法数之和。

初始条件:dp[1] = 1(到达第1阶只有1种方法),dp[2] = 2(到达第2阶有2种方法:1+1或2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2299843.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始学Python爬虫:(二)使用基本库urllib(下)

一、异常处理 关于某些情况下&#xff0c;可能会出现异常&#xff0c;如果不处理它们&#xff0c;会发生很多错误。 而urllib库提供了error模块来处理这些异常&#xff0c;该模块包括以下功能&#xff1a; &#xff08;1&#xff09;URLError 该类含有一个属性reason&#x…

【嵌入式Linux应用开发基础】read函数与write函数

目录 一、read 函数 1.1. 函数原型 1.2. 参数说明 1.3. 返回值 1.4. 示例代码 二、write 函数 2.1. 函数原型 2.2. 参数说明 2.3. 返回值 2.4. 示例代码 三、关键注意事项 3.1 部分读写 3.2 错误处理 3.3 阻塞与非阻塞模式 3.4 数据持久化 3.5 线程安全 四、嵌…

15.1 Process(进程)类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 通常开发时想要获得进程是比较困难的事&#xff0c;必须要调用CreateToolhelpSnapshot、ProcessFirst、ProcessNext等API或者诸如 Zw…

CentOS 7 企业级Redis 7部署指南

CentOS 7 企业级Redis 7部署指南 目录导航 一、环境准备 1.1 依赖管理 二、离线安装 2.1 源码编译安装2.2 目录结构规范 三、生产配置 3.1 主配置文件3.2 配置生成脚本 四、系统集成 4.1 Systemd服务文件4.2 服务管理命令 五、安全加固 5.1 网络安全配置5.2 审计配置 六、性能…

消息中间件深度剖析:以 RabbitMQ 和 Kafka 为核心

在现代分布式系统和微服务架构的构建中&#xff0c;消息中间件作为一个不可或缺的组件&#xff0c;承担着系统间解耦、异步处理、流量削峰、数据传输等重要职能。尤其是在面临大规模并发、高可用性和可扩展性需求时&#xff0c;如何选择合适的消息中间件成为了开发者和架构师们…

大语言模型简史:从Transformer(2017)到DeepSeek-R1(2025)的进化之路

2025年初&#xff0c;中国推出了具有开创性且高性价比的「大型语言模型」&#xff08;Large Language Model — LLM&#xff09;DeepSeek-R1&#xff0c;引发了AI的巨大变革。本文回顾了LLM的发展历程&#xff0c;起点是2017年革命性的Transformer架构&#xff0c;该架构通过「…

java八股文-spring

目录 1. spring基础 1.1 什么是Spring&#xff1f; 1.2 Spring有哪些优点&#xff1f; 1.3 Spring主要模块 1.4 Spring常用注解 1.5 Spring中Bean的作用域 1.6 Spring自动装配的方式 1.7 SpringBean的生命周期 1.8 多级缓存 1.9 循环依赖&#xff1f; 1 .8.1 原因 1.8…

NLP 八股 DAY1:BERT

BERT全称&#xff1a;Pre-training of deep bidirectional transformers for language understanding&#xff0c;即深度双向Transformer。 模型训练时的两个任务是预测句⼦中被掩盖的词以及判断输⼊的两个句⼦是不是上下句。在预训练 好的BERT模型后⾯根据特定任务加上相应的⽹…

蓝桥与力扣刷题(230 二叉搜索树中第k小的元素)

题目&#xff1a;给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1,4,null,2], k 1 输出&#xff1a;1示例 2&#xff…

半遮挡检测算法 Detecting Binocular Half-Occlusions

【1. 背景】&#xff1a; 本文分析【Detecting Binocular Half-Occlusions&#xff1a;Empirical Comparisons of Five Approaches】Geoffrey Egnal和Richard P. Wildes于2002年发表在IEEE Transactions on Pattern Analysis and Machine Intelligence上&#xff0c;这是1篇中…

PHP培训机构教务管理系统小程序

&#x1f511; 培训机构教务管理系统——智慧教育&#xff0c;高效管理新典范 &#x1f680; 这款教务管理系统&#xff0c;是基于前沿的ThinkPHP框架与Uniapp技术深度融合&#xff0c;匠心打造的培训机构管理神器。它犹如一把开启高效运营与精细管理的金钥匙&#xff0c;专为…

无人机不等同轴旋翼架构设计应用探究

“结果显示&#xff0c;对于不等组合&#xff0c;用户应将较小的螺旋桨置于上游以提高能效&#xff0c;但若追求最大推力&#xff0c;则两个相等的螺旋桨更为理想。” 在近期的研究《不等同轴旋翼性能特性探究》中&#xff0c;Max Miles和Stephen D. Prior博士深入探讨了不同螺…

CTFHub技能树-密码口令wp

目录 引言弱口令默认口令 引言 仅开放如下关卡 弱口令 通常认为容易被别人&#xff08;他们有可能对你很了解&#xff09;猜测到或被破解工具破解的口令均为弱口令。 打开环境&#xff0c;是如下界面&#xff0c;尝试一些弱口令密码无果 利用burpsuite抓包&#xff0c;然后爆…

【NLP251】BertTokenizer 的全部 API 及 使用案例

BertTokenizer 是 Hugging Face 的 transformers 库中用于处理 BERT 模型输入的分词器类。它基于 WordPiece 分词算法&#xff0c;能够将文本分割成词汇单元&#xff08;tokens&#xff09;&#xff0c;并将其转换为 BERT 模型可以理解的格式。BertTokenizer 是 BERT 模型的核心…

【MySQL常见疑难杂症】常见文件及其所存储的信息

1、MySQL配置文件的读取顺序 &#xff08;非Win&#xff09;/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/etc/my.cnf、&#xff5e;/.my.cnf 可以通过命令查看MySQL读取配置文件的顺序 [roothadoop01 ~]# mysql --help |grep /etc/my.cnf /etc/my.cnf /etc/mysql/my.c…

IDEA集成DeepSeek

引言 随着数据量的爆炸式增长&#xff0c;传统搜索技术已无法满足用户对精准、高效搜索的需求。 DeepSeek作为新一代智能搜索技术&#xff0c;凭借其强大的语义理解与深度学习能力&#xff0c;正在改变搜索领域的游戏规则。 对于 Java 开发者而言&#xff0c;将 DeepSeek 集成…

leetcode:627. 变更性别(SQL解法)

难度&#xff1a;简单 SQL Schema > Pandas Schema > Salary 表&#xff1a; ----------------------- | Column Name | Type | ----------------------- | id | int | | name | varchar | | sex | ENUM | | salary | int …

SQLMesh系列教程-3:SQLMesh模型属性详解

SQLMesh 的 MODEL 提供了丰富的属性&#xff0c;用于定义模型的行为、存储、调度、依赖关系等。通过合理配置这些属性&#xff0c;可以构建高效、可维护的数据管道。在 SQLMesh 中&#xff0c;MODEL 是定义数据模型的核心结构&#xff0c;初学SQLMesh&#xff0c;定义模型看到属…

【Leetcode 952】按公因数计算最大组件大小

题干 给定一个由不同正整数的组成的非空数组 nums &#xff0c;考虑下面的图&#xff1a; 有 nums.length 个节点&#xff0c;按从 nums[0] 到 nums[nums.length - 1] 标记&#xff1b;只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时&#xff0c;nums[i] 和 nums[j]之…

【第4章:循环神经网络(RNN)与长短时记忆网络(LSTM)— 4.6 RNN与LSTM的变体与发展趋势】

引言:时间序列的魔法钥匙 在时间的长河中,信息如同涓涓细流,绵延不绝。而如何在这无尽的数据流中捕捉、理解和预测,正是循环神经网络(RNN)及其变体长短时记忆网络(LSTM)所擅长的。今天,我们就来一场深度探索,揭开RNN与LSTM的神秘面纱,看看它们如何在时间序列的海洋…