当前位置: 首页 > news >正文

算法学习笔记(8)-动态规划基础篇

目录

基础内容:

动态规划:

动态规划理解的问题引入:

解析:(暴力回溯)

代码示例:

暴力搜索:

Dfs代码示例:(搜索)

暴力递归产生的递归树:

记忆化搜索:

代码示例:

动态规划:

代码示例:(动态规划,从最小子问题开始)

执行过程(动态规划):

解析:(动态规划)

空间优化:

代码示例:

解析:


基础内容:

什么是动态规划,动态规划作为一种手段可以解决哪些问题,动态规划的分类,以及具体的分类可以解决的具体问题的分类。

动态规划:

是一个重要的算法范式,它将一个问题分解成一系列更小的子问题,并通过存储子问题解避免重复计算,从而大幅度提升时间效率。

动态规划理解的问题引入:

通过爬楼梯的案例来引入这个问题,给定一个共有n阶的楼梯,你每步可以上1阶或者2阶,请问有多少种方案可以爬到楼顶。

解析:(暴力回溯)

本题目的目标是求解方案数量,我们可以考虑通过回溯来穷举所有可能性。具体来说,将爬楼梯想象为一个多轮选择的过程:从地面出发,每轮选择上一阶或者二阶,每当达到楼梯顶部时就将方案数量加1,当越过楼梯顶部就将其剪枝。

代码示例

# python代码示例
def backrack(choices,state,n,res) :if state == n :res[0] += 1 for choice in choices :if state + choice > n :continuebackrack(choices,state+choice,n,res)
def climbing_stairs_backrack(n) :choices = [1,2]state = 0res = [0]backrack(choices,state,n,res)return res[0]
n = int(input())
print(climbing_stairs_backrack(n))
// c++代码示例
void backrack(vector<int> &choices, int state, int n, vector<int> &res)
{if (state == n ){res[0]++ ;}for (auto &choice : choices){if (state + choice > n){continue ;}backrack(choices, state + choice, n, res)}
}int climbingStairsBackrack(int n)
{    vector<int> choices = {1 , 2 } ;int state = 0 ;vector<int> res = [0] ;backrack(choices, state, n, res) ;return res[0] ;
}

暴力搜索:

回溯算法通常并不显式地对问题进行拆解,而是将问题看作一系列决策步骤,通过试探和剪枝,搜索所有可能的解。

我们可以尝试从问题分解的角度分析这道题。设爬到第i阶共有dp[i]中方案,那么dp[i]就是原问题,其子问题包括:

dp[i-1],dp[i-2],dp[1],dp[2]

由于每轮只能上1阶或者2阶,因此当我们站在第i阶楼梯上时,上一轮只可能站在第i-1或者i-2台阶上。换句话说,我们只能从第i-1阶或者第i-2阶迈向第i阶。

由此便可以得出一个重要的推论:爬到第i-1阶的方案加上爬到第i-2阶的方案数就等于爬到第i阶的方案数。公式如下:

dp[i] = dp[i-1] + dp[i-2]

这就意味着,爬楼问题中存在着递推的关系,原问题可由子问题的解构建来得到解决

Dfs代码示例:(搜索)

# python 代码示例
def dfs(i : int) -> int :if i == 1 or i == 2 :return icount = dfs(i - 1) + dfs(i - 2)return count
def climbing_stairs_dfs(n : int) -> int :retunr dfs(n)
// c++ 代码示例
int dfs(int i)
{if (i == 1 || i == 2){return i ;}int count = dfs(i - 1) + dfs(i - 2);return count ;
}
int climbingStairsDFS(int n)
{retunr dfs(n) ;
}

暴力递归产生的递归树

解决上述递归树中的重复问题,采用记忆化搜索的方式,可以把大量重复构建的相同子树进行去掉,从而达到提高计算效率。(重叠子问题

记忆化搜索:

将所有重叠的子问题只进行一遍计算,需要声明一个数组nem来记录每个子问题的解,并在搜索过程中将重叠子问题剪枝。

  1. 当首次计算dp[i]时,将其记录在nem[i],便于后续的使用
  2. 当再次计算dp[i]时,直接在nem[i]中进行获取结果,避免重复子问题的计算。

代码示例:

# python 代码示例
def dfs(i : int, mem : list[int]) -> int :if i == 1 or i == 2 :return iif mem[i] != -1 :return mem[i]count = dfs(i - 1, mem) + dfs(i - 2, mem)# 记录dfs(i)mem[i] = countreturn count
def climbing_stairs_dfs_mem(n : int) -> int :mem = [-1] * (n + 1)return dfs(n, mem)
// c++ 代码示例
int dfs(int i, vector<int> &mem)
{if (i == 1 || i == 2){return i ;}if (mem != -1){return mem[i] ;}int count = dfs(i - 1, mem) + dfs(i - 2, mem) ;mem[i] = count ;return count ;
}
int climbingStairsDFSMem(int n)
{vector<int> mem(n + 1, -1) ;return dfs(n, mem) ; 
}

经过记忆化处理后,所有重叠的子问题都只计算一次,时间复杂度优化到了O(n)

动态规划:

记忆化搜索是一种”从顶至低”的方法,我们从原问题(根节点)开始,递归地将较大子问题分解成较小子问题,直至解已知的最小子问题(叶节点)。之后,通过回溯逐层收集子问题的解,构建出原问题的解。

与之相反,动态规划是一种“从底至顶”方法:从最小子问题的解开始,迭代地构建更大子问题的解,直至得到原问题的解。

由于动态规划不包含回溯过程,因此只需要使用循环迭代实现,无须使用递归。

代码示例:(动态规划,从最小子问题开始)

# python 代码示例
def clibing_stairs_dp(n) :if n == 1 or n == 2 :return ndp = [0] * (n + 1)dp[1], dp[2] = 1, 2for i in range(3,n + 1) :dp[i] = dp[i-1] + dp[i- 2]return dp[n]
// c++ 代码示例int climbingStairsDP(int n) 
{if (n == 1 || n == 2){retunr n ;}vector<int> dp(n + 1, -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] ;
}

执行过程(动态规划):

解析:(动态规划)

相似于回溯算法,动态规划也使用“状态”概念来表示问题求解的特定阶段,每个状态都对应一个子问题以及相应的局部最优解。例:爬楼梯问题的状态定义为当前所在楼梯的阶数i

根据以上内容,我们可以总结为动态术语的常用术语:

  1. 将数组dp称为{dp表},dp[i]表示状态i对应子问题的解
  2. 将最小子问题对应的状态,(第一阶和第二阶楼梯)称为初始状态
  3. 将递推公式dp[i] = dp[i-1] + dp[i-2]称为状态方程

空间优化:

dp[i] 只跟 dp[i-1] 和 dp[i-2] 有关

无须使用一个数组来存储所有子问题的解,只需要两个变量滚动前进即可。

代码示例:

# python 代码示例
def clibing_stairs_dp_comp(n) :if n == 1 or n == 2 :return na, b = 1, 2for _ in range(3, n + 1) :a, b = b , a + breturn b
// c++ 代码示例
int climbingStairsComp(int n) 
{if (n == 1 || n == 2){return n ;}int a = 1 , b = 2 ;for (int i = 3 ; i <= n ; i++){int temp = b ;b = a + b ;a = temp ;}return b ;
}

解析:

省去了数组dp所占用的空间,空间复杂度由O(n)降为O(1)

在动态规划问题中,当前状态仅与前面有限个状态有关,这时我们可以只保留必要的状态,通过“降维”来节省内存空间。这种空间优化技巧被称为“滚动变量”或“滚动数组”。

相关文章:

算法学习笔记(8)-动态规划基础篇

目录 基础内容&#xff1a; 动态规划&#xff1a; 动态规划理解的问题引入&#xff1a; 解析&#xff1a;&#xff08;暴力回溯&#xff09; 代码示例&#xff1a; 暴力搜索&#xff1a; Dfs代码示例&#xff1a;&#xff08;搜索&#xff09; 暴力递归产生的递归树&…...

数据库常见问题(持续更新)

数据库常见问题(持续更新) 1、数据库范式&#xff1f; 1NF&#xff1a;不可分割2NF&#xff1a;没有非主属性对候选码存在部分依赖3NF&#xff1a;没有非主属性传递依赖候选码BCNF&#xff1a;消除了主属性对对候选码的传递依赖或部分依赖 2、InnoDB事务的实现&#xff1f; …...

定个小目标之刷LeetCode热题(40)

94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 直接上代码吧&#xff0c;中序遍历左根右 class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> res new ArrayList<Integer>(…...

Linux--线程(概念篇)

目录 1.背景知识 再谈地址空间&#xff1a; 关于页表&#xff08;32bit机器上&#xff09; 2.线程的概念和Linux中线程的实现 概念部分&#xff1a; 代码部分&#xff1a; 问题&#xff1a; 3.关于线程的有点与缺点 4.进程VS线程 1.背景知识 再谈地址空间&#xff1a…...

Mojo: 轻量级Perl框架的魔力

在Perl的丰富生态系统中&#xff0c;Mojolicious&#xff08;简称Mojo&#xff09;是一个轻量级的实时Web框架&#xff0c;以其极简的API和强大的功能而受到开发者的喜爱。Mojo不仅适用于构建高性能的Web应用&#xff0c;还可以用来编写简单的脚本和命令行工具。本文将带你探索…...

Python 游戏服务器架构优化

优化 Python 游戏服务器的架构涉及多个方面&#xff0c;包括性能、可伸缩性、并发处理和网络通信。下面是一些优化建议&#xff1a; 1、问题背景 在设计 Python 游戏服务器时&#xff0c;如何实现服务器的横向扩展&#xff0c;以利用多核处理器的资源&#xff0c;并确保服务器…...

13 学习总结:指针 · 其一

目录 一、内存和地址 &#xff08;一&#xff09;内存 &#xff08;二&#xff09;内存单元 &#xff08;三&#xff09;地址 &#xff08;四&#xff09;拓展&#xff1a;CPU与内存的联系 二、指针变量和地址 &#xff08;一&#xff09;创建变量的本质 &#xff08;二…...

golang 项目打包部署环境变量设置

最近将 golang 项目打包部署在不同环境&#xff0c;总结一下自己的心得体会&#xff0c;供大家参考。 1、首先要明确自己目标服务器的系统类型(例如 windows 或者Linux) &#xff0c;如果是Linux 还需要注意目标服务器的CPU架构(amd或者arm) 目标服务器的CPU架构可执行命令&…...

【Linux进程】进程优先级 Linux 2.6内核进程的调度

目录 前言 1. 进程优先级 2. 并发 3. Linux kernel 2.6 内核调度队列与调度原理 总结 前言 进程是资源分配的基本单位, 在OS中存在这很多的进程, 那么就必然存在着资源竞争的问题, 操作系统是如何进行资源分配的? 对于多个进程同时运行, 操作系统又是如何调度达到并发呢?…...

Linux中的粘滞位及mysql日期函数

只要用户具有目录的写权限, 用户就可以删除目录中的文件, 而不论这个用户是否有这个文件的写 权限. 为了解决这个不科学的问题, Linux引入了粘滞位的概念. 粘滞位 当一个目录被设置为"粘滞位"(用chmod t),则该目录下的文件只能由 一、超级管理员删除 二、该目录…...

BP神经网络的实践经验

目录 一、BP神经网络基础知识 1.BP神经网络 2.隐含层选取 3.激活函数 4.正向传递 5.反向传播 6.不拟合与过拟合 二、BP神经网络设计流程 1.数据处理 2.网络搭建 3.网络运行过程 三、BP神经网络优缺点与改进方案 1.BP神经网络的优缺点 2.改进方案 一、BP神经网络基…...

PCL 点云FPFH特征描述子

点云FPFH特征描述子 一、概述1.1 FPFH概念1.2 基本原理1.3 PFH和FPFH的区别二、代码实现三、结果示例一、概述 1.1 FPFH概念 快速点特征直方图(FPFH)描述子:计算 PFH 特征的效率其实是十分低的,这样的算法复杂度无法实现实时或接近实时的应用。因此,这篇文章将介绍 PFH 的简…...

基于golang的文章信息抓取

基于golang的文章信息抓取 学习golang爬虫&#xff0c;实现广度爬取&#xff0c;抓取特定的网页地址&#xff1a;测试站点新笔趣阁&#xff08;https://www.xsbiquge.com/&#xff09; 主要学习golang的goroutine和channel之间的协作&#xff0c;无限爬取站点小说的地址仅限书目…...

【手撕数据结构】卸甲时/空间复杂度

目录 前言时间复杂度概念⼤O的渐进表⽰法小试牛刀 空间复杂度 前言 要想知道什么是空/时间复杂度,就得知道什么是数据结构。 这得分两层来理解。我们生活中处处存在数据&#xff0c;什么抖音热点上的国际大事&#xff0c;什么懂的都懂的雍正卸甲等等一系列我们用户看得到的&a…...

消防认证-防火窗

一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准&#xff0c;且通过了国家认证认可监督管理委员会审批&#xff0c;获得消防认证资质的认证机构颁发的证书&#xff0c;消防产品具有完好的防火功能&#xff0c;是住房和城乡建设领域验收的重要指标。 二、认证依据…...

C++进阶-二叉树进阶(二叉搜索树)

1. 二叉搜索树 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 1.若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值2.若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于…...

【Unity小知识】UnityEngine.UI程序集丢失的问题

问题表现 先来说一下问题的表现&#xff0c;今天在开发的时候工程突然出现了报错&#xff0c;编辑器提示UnityEngine.UI缺少程序集引用。 问题分析与解决&#xff08;一&#xff09; 既然是程序集缺失&#xff0c;我们首先查看一下工程项目是否引用了程序集。在项目引用中查找一…...

CentOS 离线安装部署 MySQL 8详细教程

1、简介 MySQL是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它基于SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;进行操作。MySQL最初由瑞典的MySQL AB公司开发&#xff0c;后来被Sun Microsystems公司…...

云计算【第一阶段(28)】DNS域名解析服务

一、DNS解析的定义与作用 1.1、DNS解析的定义 DNS解析&#xff08;Domain Name System Resolution&#xff09;是互联网服务中的一个核心环节&#xff0c;它负责将用户容易记住的域名转换成网络设备能够识别和使用的IP地址。一般来讲域名比 IP 地址更加的有含义、也更容易记住…...

pygame 音乐粒子特效

代码 import pygame import numpy as np import pymunk from pymunk import Vec2d import random import librosa import pydub# 初始化pygame pygame.init()# 创建屏幕 screen pygame.display.set_mode((1920*2-10, 1080*2-10)) clock pygame.time.Clock()# 加载音乐文件 a…...

Linux dmesg实战指南:从内核消息解析到故障排查(附实用技巧与常见问题)

1. 初识dmesg&#xff1a;你的Linux系统健康检查仪 刚接触Linux系统管理时&#xff0c;我总把dmesg当成"高级版系统日志"。直到有次服务器突然宕机&#xff0c;才发现这个命令简直就是系统故障的"黑匣子"。想象一下&#xff0c;当你的电脑突然蓝屏&#xf…...

别等电脑挂了后悔,教你现在就查看Bitlocker密钥

网管小贾 / sysadm.cc陈主任晃了晃脑袋&#xff0c;皱着眉冲着刘晓白说道&#xff1a;“简历我看过了&#xff0c;就算请我吃饭&#xff0c;恐怕也很难办啊&#xff01;” 刘晓白则一呲牙&#xff1a;“我说老舅&#xff0c;要进你们公司&#xff0c;还不是您一句话的事儿嘛&am…...

StructBERT中文情感WebUI多语言支持:中英双语界面切换与结果输出

StructBERT中文情感WebUI多语言支持&#xff1a;中英双语界面切换与结果输出 1. 项目介绍与核心价值 如果你正在寻找一个能快速上手、效果不错的中文情感分析工具&#xff0c;那么今天介绍的StructBERT中文情感分析WebUI&#xff0c;可能就是你的理想选择。这个项目基于百度开…...

FPGA新手避雷指南:你的第一个呼吸灯项目可能卡在这几个Vivado仿真和引脚分配问题上

FPGA新手避雷指南&#xff1a;从仿真到引脚分配的完整呼吸灯实战 第一次在FPGA上实现呼吸灯效果&#xff0c;本该是充满成就感的时刻。但当你按照教程一步步操作&#xff0c;点击"Generate Bitstream"后&#xff0c;板子上的LED却毫无反应——这种挫败感我太熟悉了。…...

Winhance中文版:让Windows系统管理不再复杂的全能工具

Winhance中文版&#xff1a;让Windows系统管理不再复杂的全能工具 【免费下载链接】Winhance-zh_CN A Chinese version of Winhance. C# application designed to optimize and customize your Windows experience. 项目地址: https://gitcode.com/gh_mirrors/wi/Winhance-zh…...

Z-Image-Turbo-辉夜巫女数据预处理实战:模拟VLOOKUP实现提示词与风格模板匹配

Z-Image-Turbo-辉夜巫女数据预处理实战&#xff1a;模拟VLOOKUP实现提示词与风格模板匹配 你有没有遇到过这样的烦恼&#xff1f;每次用AI画图&#xff0c;想生成一个“赛博朋克”风格的图片&#xff0c;都得重新回忆或者翻找之前写好的那一长串复杂的提示词。或者团队里每个人…...

LangFlow+Ollama快速部署:3步搭建本地AI应用开发环境

LangFlowOllama快速部署&#xff1a;3步搭建本地AI应用开发环境 想快速搭建一个属于自己的AI应用开发环境&#xff0c;但又不想折腾复杂的命令行和配置&#xff1f;今天&#xff0c;我来分享一个极其简单的方法&#xff1a;用LangFlow和Ollama&#xff0c;只需3步&#xff0c;…...

光伏板缺陷检测实战:从数据集构建到YOLO模型训练全流程解析

1. 光伏板缺陷检测的现实意义 光伏发电作为清洁能源的重要组成部分&#xff0c;其运维效率直接影响发电量收益。我在实地考察中发现&#xff0c;一块被鸟粪覆盖的光伏板&#xff0c;发电效率可能下降30%以上&#xff1b;而热斑效应更会导致组件永久性损伤。传统人工巡检每天最多…...

HarmonyOS 音乐播放器进阶实战——AVPlayer状态管理与播放列表

1. AVPlayer状态机深度解析 在HarmonyOS音乐播放器开发中&#xff0c;AVPlayer的状态管理就像驾驶手动挡汽车——你需要清楚知道当前处于哪个档位&#xff0c;才能平稳切换。我曾在项目中因为状态处理不当导致音乐卡顿&#xff0c;后来才发现是状态机流转出了问题。 AVPlayer…...

终极指南:如何用btcrecover找回你忘记的比特币钱包密码 [特殊字符]️

终极指南&#xff1a;如何用btcrecover找回你忘记的比特币钱包密码 &#x1f5dd;️ 【免费下载链接】btcrecover An open source Bitcoin wallet password and seed recovery tool designed for the case where you already know most of your password/seed, but need assist…...