算法(四)——动态规划
文章目录
- 基本思想
- 适用条件
- 最优子结构
- 子问题重叠
- 状态转移方程
- 解题步骤
- 应用
- 斐波那契数列
- 背包问题
- 最大子数组和
基本思想
动态规划的核心思想在于将一个复杂的问题分解为一系列相互关联的子问题,通过求解子问题并保存其解,避免对相同子问题的重复计算,从而提高算法的效率。具体来说,动态规划通常会利用已经解决的子问题的结果来推导出更大规模子问题的解,直至最终解决原问题。
适用条件
最优子结构
问题的最优解包含其子问题的最优解。也就是说,一个问题的最优解可以由其子问题的最优解组合而成。例如,在求解最短路径问题时,从起点到终点的最短路径必然包含从起点到中间某个节点的最短路径。
子问题重叠
在求解问题的过程中,会多次遇到相同的子问题。通过保存这些子问题的解,避免重复计算,从而提高算法的效率。例如,在斐波那契数列的计算中,计算较大的斐波那契数时会多次用到较小的斐波那契数。
状态转移方程
用于描述问题的状态和状态之间的关系,通过状态的转移得到最终问题的解。
解题步骤
定义状态:确定问题的状态表示,即如何用一个或多个变量来描述问题的子问题。状态的定义需要能够准确地刻画问题的特征,并且要满足最优子结构性质。
找出状态转移方程:根据问题的最优子结构性质,找出状态之间的递推关系,即如何从已知的子问题的解推导出当前问题的解。状态转移方程是动态规划算法的核心。
确定初始状态:找出问题的边界条件,即最简单的子问题的解。初始状态是递推的起点,后续的状态都是基于初始状态逐步推导出来的。
计算顺序:根据状态转移方程,确定状态的计算顺序。通常有两种计算顺序:自顶向下(记忆化搜索)和自底向上(迭代)。自顶向下方法从原问题出发,递归地求解子问题,并保存已经求解的子问题的解;自底向上方法则从初始状态开始,逐步计算出所有子问题的解,直到得到原问题的解。
返回结果:根据问题的要求,从计算得到的状态中提取出最终的解。
应用
斐波那契数列
public class Fibonacci {public static int fibonacci(int n) { if (n <= 1) return n; int[] dp = new int[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]; } public static void main(String[] args) { System.out.println(fibonacci(10)); }}
- 子问题定义:定义 dp[i] 表示第 i 个斐波那契数。
- 状态转移方程: dp[i] = dp[i - 1] + dp[i - 2] ,其中 i >= 2 , dp[0] = 0 , dp[1] = 1 。- 时间复杂度:使用了一个循环来计算 dp 数组的每个元素,循环次数为 n ,因此时间复杂度为 O(n) 。
- 空间复杂度:使用了一个大小为 n + 1 的数组 dp 来存储子问题的解,所以空间复杂度为 O(n)。
- 实际上,由于计算 dp[i] 时只需要 dp[i - 1] 和 dp[i - 2] 的值,我们可以进一步优化空间复杂度到 ,只使用两个变量来存储前两个斐波那契数。
背包问题
public class Knapsack {public static int knapsack(int[] weights, int[] values, int capacity) { int n = weights.length; int[][] dp = new int[n + 1][capacity + 1]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= capacity; j++) { if (weights[i - 1] <= j) { dp[i][j] = Math.max(values[i - 1] + dp[i - 1][j - weights[i - 1]], dp[i - 1][j]); } else { dp[i][j] = dp[i - 1][j]; } } } return dp[n][capacity]; } public static void main(String[] args) { int[] weights = {2, 3, 4, 5}; int[] values = {3, 4, 5, 6}; int capacity = 8; System.out.println(knapsack(weights, values, capacity)); }}
- 子问题定义:定义 dp[i][j] 表示在前 i 个物品中选择,且背包容量为 j 时能获得的最大价值。
- 状态转移方程:
- 当 weights[i - 1] <= j 时(即第 i 个物品可以放入背包), dp[i][j] = Math.max(values[i - 1] + dp[i - 1][j - weights[i - 1]], dp[i - 1][j]) ,表示取放入第 i 个物品和不放入第 i 个物品两种情况的较大值。
- 当 weights[i - 1] > j 时(即第 i 个物品放不下), dp[i][j] = dp[i - 1][j] ,即不放入第 i 个物品。
- 时间复杂度:有两个嵌套的循环,外层循环遍历物品数量 n 次,内层循环遍历背包容量 capacity 次,所以时间复杂度为 O(n×capacity) 。
- 空间复杂度:使用了一个二维数组 dp[n + 1][capacity + 1] 来存储子问题的解,因此空间复杂度为O(n×capacity) 。通过优化,可以将空间复杂度降低到 ,因为每次计算 dp[i][j] 时只依赖于 dp[i - 1][…] 的值。
最大子数组和
假设有一个数组 nums,求解其连续子数组的最大和
- 定义状态: 设 dp[i] 为以 nums[i] 结尾的连续子数组的最大和。
- 状态转移方程: dp[i] = max(dp[i-1] + nums[i], nums[i]),即当前位置的最大和要么是之前的最大和加上当前元素,要么是当前元素本身。
- 初始化: dp[0] = nums[0],数组的第一个元素作为初始值。
- 遍历: 从数组的第二个元素开始遍历,更新 dp[i]。
- 最终结果: 最大的 dp[i] 即为所求。
public class MaxSubarraySum {public static int maxSubarraySum(int[] nums) {int n = nums.length;// 创建一个数组 dp 用于保存子问题的解int[] dp = new int[n];// 初始化 dp 数组的第一个元素dp[0] = nums[0];// 遍历数组,根据状态转移方程更新 dp 数组for (int i = 1; i < n; i++) {dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);}// 找出 dp 数组中的最大值int max = dp[0];for (int i = 1; i < n; i++) {if (dp[i] > max) {max = dp[i];}}return max;}public static void main(String[] args) {int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};int result = maxSubarraySum(nums);System.out.println(result); // 输出 6,对应子数组 [4, -1, 2, 1]}
}
相关文章:
算法(四)——动态规划
文章目录 基本思想适用条件最优子结构子问题重叠状态转移方程 解题步骤应用斐波那契数列背包问题最大子数组和 基本思想 动态规划的核心思想在于将一个复杂的问题分解为一系列相互关联的子问题,通过求解子问题并保存其解,避免对相同子问题的重复计算&am…...
博客系统完整开发流程
前言 通过前⾯课程的学习, 我们掌握了Spring框架和MyBatis的基本使用, 并完成了图书管理系统的常规功能开发, 接下来我们系统的从0到1完成⼀个项⽬的开发. 企业开发的流程 1. 需求评审(产品经理(PM)会和运营(想口号),UI,测试,开发等沟通) ,会涉及到背景/目标/怎么做,可能会有多…...
【C语言】指针笔试题
前言:上期我们介绍了sizeof与strlen的辨析以及sizeof,strlen相关的一些笔试题,这期我们主要来讲指针运算相关的一些笔试题,以此来巩固我们之前所学的指针运算! 文章目录 一,指针笔试题1,题目一…...
大数据开发平台的框架
根据你的需求,以下是从 GitHub 推荐的 10 个可以实现大数据开发平台的项目: 1. Apache Spark Apache Spark 是一个开源的分布式计算框架,适用于大规模数据处理和分析。它提供了强大的数据处理能力,支持实时数据处理、机器学习和…...
【Python爬虫(53)】从入门到精通:Scrapy Spider开发全攻略
【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取ÿ…...
《Keras 3 : 使用迁移学习进行关键点检测》:此文为AI自动翻译
《Keras 3 :使用迁移学习进行关键点检测》 作者:Sayak Paul,由 Muhammad Anas Raza 转换为 Keras 3 创建日期:2021/05/02 最后修改时间:2023/07/19 描述:使用数据增强和迁移学习训练关键点检测器。 (i) 此示例使用 Keras 3 在 Colab 中查看 GitHub 源 关键点检测包…...
CentOS停服后的替代选择:openEuler、Rocky Linux及其他系统的未来展望
CentOS停服后的替代选择:openEuler、Rocky Linux及其他系统的未来展望 引言CentOS停服的背景华为openEuler:面向未来的开源操作系统1. 简介2. 特点3. 发展趋势 Rocky Linux:CentOS的精神继承者1. 简介2. 特点3. 发展趋势 其他可选的替代系统1…...
【Qt】桌面应用开发 ------ 绘图事件和绘图设备 文件操作
文章目录 9、绘图事件和绘图设备9.1 QPainter9.2 手动触发绘图事件9.3 绘图设备9.3.1 QPixmap9.3.2 QImage9.3.3 QImage与QPixmap的区别9.3.4 QPicture 10、文件操作10.1 文件读写10.2 二进制文件读写10.3 文本文件读写10.4 综合案例 9、绘图事件和绘图设备 什么时候画&#x…...
python与C系列语言的差异总结(3)
与其他大部分编程语言不一样,Python使用空白符(whitespace)和缩进来标识代码块。也就是说,循环体、else条件从句之类的构成,都是由空白符加上冒号(:)来确定的。大部分编程语言都是使用某种大括号来标识代码块的。下面的…...
OpenCV(9):视频处理
1 介绍 视频是由一系列连续的图像帧组成的,每一帧都是一幅静态图像。视频处理的核心就是对这些图像帧进行处理。常见的视频处理任务包括视频读取、视频播放、视频保存、视频帧处理等。 视频分析: 通过视频处理技术,可以分析视频中的运动、目标、事件等。…...
【C++设计模式】观察者模式(1/2):从基础到优化实现
1. 引言 在 C++ 软件与设计系列课程中,观察者模式是一个重要的设计模式。本系列课程旨在深入探讨该模式的实现与优化。在之前的课程里,我们已对观察者模式有了初步认识,本次将在前两次课程的基础上,进一步深入研究,着重解决观察者生命周期问题,提升代码的安全性、灵活性…...
2025年华为手机解锁BL的方法
注:本文是我用老机型测试的,新机型可能不适用 背景 华为官方已经在2018年关闭了申请BL解锁码的通道,所以华为手机已经无法通过官方获取解锁码。最近翻出了一部家里的老手机华为畅玩5X,想着能不能刷个系统玩玩,但是卡…...
在 CentOS 7.9上部署 Oracle 11.2.0.4.0 数据库
目录 在 CentOS 7.9上部署 Oracle 11.2.0.4.0 数据库引言安装常见问题vim粘贴问题 环境情况环境信息安装包下载 初始环境准备关闭 SELinux关闭 firewalld 安装前初始化工作配置主机名安装依赖优化内核参数限制 Oracle 用户的 Shell 权限配置 PAM 模块配置swap创建用户组与用户,…...
idea里的插件spring boot helper 如何使用,有哪些强大的功能,该如何去习惯性的运用这些功能
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
Docker 搭建 Redis 数据库
Docker 搭建 Redis 数据库 前言一、准备工作二、创建 Redis 容器的目录结构三、启动 Redis 容器1. 通过 redis.conf 配置文件设置密码2. 通过 Docker 命令中的 requirepass 参数设置密码 四、Host 网络模式与 Port 映射模式五、检查 Redis 容器状态六、访问 Redis 服务总结 前言…...
JAVAweb之过滤器,监听器
文章目录 过滤器认识生命周期FilterConfigFilterChain过滤器执行顺序应用场景代码 监听器认识ServletContextListenerHttpSessionListenerServletRequestListener代码 过滤器 认识 Java web三大组件之一,与Servlet相似。过滤器是用来拦截请求的,而非处…...
计算机毕业设计SpringBoot+Vue.js足球青训俱乐部管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
基于 DeepSeek LLM 本地知识库搭建开源方案(AnythingLLM、Cherry、Ragflow、Dify)认知
写在前面 博文内容涉及 基于 Deepseek LLM 的本地知识库搭建使用 ollama 部署 Deepseek-R1 LLM知识库能力通过 Ragflow、Dify 、AnythingLLM、Cherry 提供理解不足小伙伴帮忙指正 😃,生活加油 我站在人潮中央,思考这日日重复的生活。我突然想,…...
QSplashScreen --软件启动前的交互
目录 QSplashScreen 类介绍 使用方式 项目中使用 THPrinterSplashScreen头文件 THPrinterSplashScreen实现代码 使用代码 使用效果 QSplashScreen 类介绍 QSplashScreen 是 Qt 中的一个类,用于显示启动画面。它通常在应用程序启动时显示,以向用户显…...
「软件设计模式」责任链模式(Chain of Responsibility)
深入解析责任链模式:用C打造灵活的请求处理链 引言:当审批流程遇上设计模式 在软件系统中,我们经常会遇到这样的场景:一个请求需要经过多个处理节点的判断,每个节点都有权决定是否处理或传递请求。就像企业的请假审批…...
蓝桥杯嵌入式客观题以及解释
第十一届省赛(大学组) 1.稳压二极管时利用PN节的反向击穿特性制作而成 2.STM32嵌套向量终端控制器NVIC具有可编程的优先等级 16 个 3.一个功能简单但是需要频繁调用的函数,比较适用内联函数 4.模拟/数字转换器的分辨率可以通过输出二进制…...
你对WebAssembly的看法是什么?
WebAssembly(Wasm)是一种新兴的技术,旨在通过提供一种新的低级字节码格式来提高 Web 应用程序的性能和效率。它与 JavaScript 互补,使得开发者可以将其他编程语言(如 C、C、Rust 等)编译为高效的字节码&…...
Qt在Linux嵌入式开发过程中复杂界面滑动时卡顿掉帧问题分析及解决方案
Qt在Linux嵌入式设备开发过程中,由于配置较低,加上没有GPU,我们有时候会遇到有些组件比较多的复杂界面,在滑动时会出现掉帧或卡顿的问题。要讲明白这个问题还得从CPU和GPU的分工说起。 一、硬件层面核心问题根源剖析 CPU&#x…...
vscode 版本
vscode官网 Visual Studio Code - Code Editing. Redefined 但是官网只提供最新 在之前的版本就要去github找了 https://github.com/microsoft/vscode/releases 获取旧版本vscode安装包的方法_vscode 老版本-CSDN博客...
low rank decomposition如何用于矩阵的分解
1. 什么是矩阵分解和低秩分解 矩阵分解是将一个矩阵表示为若干结构更简单或具有特定性质的矩阵的组合或乘积的过程。低秩分解(Low Rank Decomposition)是其中一种方法,旨在将原矩阵近似为两个或多个秩较低的矩阵的乘积,从而降低复…...
C# string转unicode字符
在 C# 中,将字符串转换为 Unicode 字符(即每个字符的 Unicode 码点)可以通过遍历字符串中的每个字符并获取其 Unicode 值来实现。Unicode 值是一个整数,表示字符在 Unicode 标准中的唯一编号。 以下是实现方法: 1. 获…...
51单片机-串口通信编程
串行口工作之前,应对其进行初始化,主要是设置产生波特率的定时器1、串行口控制盒中断控制。具体步骤如下: 确定T1的工作方式(编程TMOD寄存器)计算T1的初值,装载TH1\TL1启动T1(编程TCON中的TR1位…...
Fisher信息矩阵与Hessian矩阵:区别与联系全解析
Fisher信息矩阵与Hessian矩阵:区别与联系全解析 在统计学和机器学习中,Fisher信息矩阵(FIM)和Hessian矩阵是两个经常出现的概念,它们都与“二阶信息”有关,常用来描述函数的曲率或参数的敏感性。你可能听说…...
有哪些开源大数据处理项目使用了大模型
以下是一些使用了大模型的开源大数据处理项目: 1. **RedPajama**:这是一个开源项目,使用了LLM大语言模型数据处理组件,对GitHub代码数据进行清洗和处理。具体流程包括数据清洗、过滤低质量样本、识别和删除重复样本等步骤。 2. …...
ubuntu离线安装Ollama并部署Llama3.1 70B INT4
文章目录 1.下载Ollama2. 下载安装Ollama的安装命令文件install.sh3.安装并验证Ollama4.下载所需要的大模型文件4.1 加载.GGUF文件(推荐、更容易)4.2 加载.Safetensors文件(不建议使用) 5.配置大模型文件 参考: 1、 如…...
