7 动态规划

下面的例子不错: 对于动态规划,能学到不少东西;

你要清楚每一步都在做什么,划分细致就能够拆解清楚!

 xk. - 力扣(LeetCode)

labuladong的算法笔记-动态规划-CSDN博客

动态规划是一种强大的算法设计策略,用于解决具有重叠子问题和最优子结构特点的问题。在面对动态规划类题目时,遵循以下步骤可以帮助你系统地解决问题:

1. 定义状态

  • 确定变量:识别哪些变量会影响问题的解。例如,在背包问题中,关键变量可能是物品的重量和价值,以及剩余的背包容量。
  • 状态表示:用这些变量定义状态。例如,dp[i][w] 可能表示前i个物品放入容量为w的背包所能获得的最大价值。

2. 状态转移方程

  • 建立关系:找到状态之间的关系,即如何从一个状态转移到另一个状态。这通常涉及到一个递推公式。例如,在斐波那契数列中,F(n) = F(n-1) + F(n-2)
  • 边界条件:确定递推公式的起始状态,通常是最简单的情况,例如 dp[0][w] = 0(背包问题中没有物品时的价值)。

3. 选择方向

  • 自底向上:从最简单的状态开始,逐步构建更复杂的状态。这种方法通常使用循环实现,避免了重复计算。
  • 自顶向下:从复杂的状态开始,递归地解决子问题。这种方法通常使用递归和记忆化(memoization)来避免重复计算。

4. 初始化

  • 初始状态:根据问题的性质初始化DP数组。例如,所有状态初始化为0或无穷大。

5. 计算

  • 填充DP表:根据状态转移方程填充DP表或数组。确保按正确的顺序填充,以便在计算每个状态时,所需的前驱状态已经被计算。

6. 返回结果

  • 解析答案:DP过程完成后,根据问题要求解析出最终答案。这可能是DP表中的某个特定值,也可能是回溯整个DP过程找到最优解的具体方案。

7. 复杂度分析

  • 时间复杂度:通常由状态的数量和状态转移的复杂度决定。
  • 空间复杂度:由存储状态所需的空间决定,可以通过滚动数组等方式优化空间复杂度。

1 70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

这是一个简单的动态规划的问题:

分解问题:不积硅步无以至千里!

假设:当前到了第x层,并且小于x层的走法f(x)我们都知道。

那么后面如何求呢?

  1. 第一个阶梯、第二个阶梯都是1下就能走到!
  2. y = x+1,那么 f(y) = f(y-1) + f(y-2), 想要上到第y步, 一定是从前面阶梯走过来的。

class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [1] * (n+1)
        
        for i in range(2,n+1):
            dp[i] = dp[i-1] + dp[i-2]
        #print(dp)
        return dp[n]

2 198. 打家劫舍 

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

相邻不能同时偷!

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

在做这一个题目的时候:

f(x): 到第x个房间能得到的最大收益;

我也是设定:加入到了第X个房间,那么之前的状态(到房间能得到的最大收益)我都是知道的。所以,f(X+1) 怎么做才能最大呢?

怎么能偷到x+1个房子,由x-1过来的,x-2过来的(开始我没考虑到这点)。

class Solution:
    def rob(self, nums: List[int]) -> int:
        dp = nums[::]

        for i in range(2,len(nums)):
            temp = dp[i-2]
            if i-3>=0:
                temp = max(temp,dp[i-3])
            dp[i] = temp + nums[i]
        
        return max(dp)

3 322. 零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1
  1. 递归;
  2. 动态规划;

有硬币:【q,w,e】

思想: 

比如7个硬币怎么使用最少的硬币进行组合呢?

f(7) = min(f(7-q),f(7-w),f(7-e)) + 1

还有个特殊条件: f(7-q),f(7-w),f(7-e) 存在组合(基石,不然无法站住脚);

我这个思路不是特征的好。

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:

        if amount==0:
            return 0 
            
        coins = sorted(coins)

        dp = [0] * (amount+1)

        for i in range(amount+1):
            for coin in coins:
                if i-coin==0:
                    dp[i] = 1
                elif i-coin>0:
                    if dp[i]==0:
                        # 
                        if dp[i-coin]==0:
                            dp[i]==0
                        else:
                            dp[i] = dp[i-coin] + 1 #min(, dp[i])
                    else:
                        if dp[i-coin]==0:
                            dp[i]==0
                        else:
                            dp[i] = min(dp[i-coin] + 1, dp[i])
                else:
                    break
        print(dp)
        return -1 if dp[amount]==0 else dp[amount]

        
        
        # def sub_x(amount):
        #     if amount==0:
        #         return 0

        #     if amount < 0 or amount<coins[0]:
        #         return -1

        #     temp = -1
        #     for coin in coins:
        #         x = sub_x(amount - coin) # -1, >=0
        #         if x == -1:
        #             continue
        #         if temp==-1:
        #             temp = x+1
        #         else:
        #             temp = min(x+1, temp)
        #     return temp

        return sub_x(amount)


思路二 :陈奕迅的背包

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        
        n = len(coins)
        dp = [[amount+1] * (amount+1) for _ in range(n+1)]    # 初始化为一个较大的值,如 +inf 或 amount+1
        # 合法的初始化
        dp[0][0] = 0    # 其他 dp[0][j]均不合法
        
        # 完全背包:套用0-1背包【遍历硬币数目k】
        for i in range(1, n+1):                     # 第一层循环:遍历硬币
            for j in range(amount+1):               # 第二层循环:遍历背包
                for k in range(j//coins[i-1]+1):    # 第三层循环:当前硬币coin取k个 (k*coin<=amount)
                    dp[i][j] = min( dp[i][j], dp[i-1][j-k*coins[i-1]] + k )

        ans = dp[n][amount] 
        return ans if ans != amount+1 else -1

 思想:

  1. dp[i][j]: 使用i个硬币拼成J元最小个数;
  2. 如何判断是否放入第i+1 个硬币呢? 当前的容量不足以满足硬币金额,那么最好的揭发就是dp[i-1][j], 最好的解决策略在之前。 当前的容量>金额: 有操作的空间, min(放入+1,不放入)
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        # 11 [1,2,5]
        coin_len = len(coins)
        dp = [[amount+1]*(amount+1) for _ in range(coin_len+1)]
        #coins = sorted(coins)
        # 多大空间
        dp[0][0] = 0

        for i in range(1,coin_len+1):
            for j in range(amount+1):
                coin = coins[i-1]
                if j < coin:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = min(dp[i-1][j], dp[i][j-coin]+1)
        # for j in range(1, coin_len+1):
        #     coin = coins[j-1]
        #     for i in range(amount+1):
        #         # 当前能够到达的最大距离
        #         for x in range(i//coin+1):
        #             dp[j][i] = min(dp[j][i], dp[j-1][i-coin*x]+x)
        #print(dp)
        return -1 if dp[coin_len][amount]==(amount+1) else dp[coin_len][amount]

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nginx的正向代理和反向代理以及tomcat

nginx的正向代理和反向代理&#xff1a; 正向代理以及缓存配置&#xff1a; 代理&#xff1a;客户端不再是直接访问服务端&#xff0c;通过代理服务器访问服务端。 正向代理&#xff1a;面向客户端&#xff0c;我们通过代理服务器的IP地址访问目标范围端。 服务端只知道代理…

绝区叁--如何在移动设备上本地运行LLM

随着大型语言模型 (LLM)&#xff08;例如Llama 2和Llama 3&#xff09;不断突破人工智能的界限&#xff0c;它们正在改变我们与周围技术的互动方式。这些模型早已集成到我们的手机中&#xff0c;但到目前为止&#xff0c;它们理解和处理请求的能力还非常有限。然而&#xff0c;…

【C++】模板进阶--保姆级解析(什么是非类型模板参数?什么是模板的特化?模板的特化如何应用?)

目录 一、前言 二、什么是C模板&#xff1f; &#x1f4a6;泛型编程的思想 &#x1f4a6;C模板的分类 三、非类型模板参数 ⚡问题引入⚡ ⚡非类型模板参数的使用⚡ &#x1f525;非类型模板参数的定义 &#x1f525;非类型模板参数的两种类型 &#x1f52…

使用 ESP32-WROOM + DHT11 做个无屏温湿度计

最近梅雨天&#xff0c;有个房间湿度很大&#xff0c;而我需要远程查看温湿度&#xff0c;所以无所谓有没有显示屏&#xff0c;某宝上的温湿度计都是带屏的&#xff0c;如果连WIFI查看温湿度操作也比较麻烦&#xff0c;还需要换电池&#xff0c;实在不能满足我的需求&#xff0…

剖析DeFi交易产品之UniswapV3:交易路由合约

本文首发于公众号&#xff1a;Keegan小钢 SwapRouter 合约封装了面向用户的交易接口&#xff0c;但不再像 UniswapV2Router 一样根据不同交易场景拆分为了那么多函数&#xff0c;UniswapV3 的 SwapRouter 核心就只有 4 个交易函数&#xff1a; exactInputSingle&#xff1a;指…

Vue进阶(四十五)Jest集成指南

文章目录 一、前言二、环境检测三、集成问题汇总四、拓展阅读 一、前言 在前期博文《Vue进阶&#xff08;八十八&#xff09;Jest》中&#xff0c;讲解了Jest基本用法及应用示例。一切顺利的话&#xff0c;按照文档集成应用即可&#xff0c;但是集成过程中遇到的问题可能五花八…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第55课-芝麻开门(语音 识别 控制3D纪念馆开门 和 关门)

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第55课-芝麻开门&#xff08;语音识别控制3D纪念馆开门和关门&#xff09; 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtn…

KVM使用命令行添加新磁盘(注:支持热插拔)

1、使用qemu-img创建格式为qcow2的磁盘 [rootkvm ~]# qemu-img create -f qcow2 /var/lib/libvirt/images/test-disk.qcow2 15G 2、显示虚拟机硬盘列表&#xff0c;查看未使用的target [rootkvm ~]# virsh domblklist kvm-client 3、添加硬盘到kvm-client虚拟机中 [rootkvm…

SpringBoot | 大新闻项目后端(redis优化登录)

该项目的前篇内容的使用jwt令牌实现登录认证&#xff0c;使用Md5加密实现注册&#xff0c;在上一篇&#xff1a;http://t.csdnimg.cn/vn3rB 该篇主要内容&#xff1a;redis优化登录和ThreadLocal提供线程局部变量&#xff0c;以及该大新闻项目的主要代码。 redis优化登录 其实…

html+css+js图片手动轮播

源代码在界面图片后面 轮播演示用的几张图片是Bing上的&#xff0c;直接用的几张图片的URL&#xff0c;谁加载可能需要等一下&#xff0c;现实中替换成自己的图片即可 关注一下点个赞吧&#x1f604; 谢谢大佬 界面图片 源代码 <!DOCTYPE html> <html lang&quo…

C++继承初识

一。继承 1.继承本质是复用相同的代码&#xff08;属性&#xff09; 2.格式&#xff1a;class 类名&#xff1a;继承方式 父类 3.继承方式的规律&#xff1a; 父类的&#xff1a; 对于私有成员&#xff0c;不管哪种继承方式都不可见--->不想被子类继承的成员 对于保护…

代码随想录——划分字母区间(Leetcode763)

题目链接 贪心 class Solution {public List<Integer> partitionLabels(String s) {int[] count new int[27];Arrays.fill(count,0);// 统计元素最后一次出现的位置for(int i 0; i < s.length(); i){count[s.charAt(i) - a] i;}List<Integer> res new Ar…

非对称加密算法原理与应用2——RSA私钥加密文件

作者:私语茶馆 1.相关章节 (1)非对称加密算法原理与应用1——秘钥的生成-CSDN博客 第一章节讲述的是创建秘钥对,并将公钥和私钥导出为文件格式存储。 本章节继续讲如何利用私钥加密内容,包括从密钥库或文件中读取私钥,并用RSA算法加密文件和String。 2.私钥加密的概述…

JDK都出到20多了,你还不会使用JDK8的Stream流写代码吗?

目录 前言 Stream流 是什么&#xff1f; 为什么要用Steam流 常见stream流使用案例 映射 map() & 集合 collect() 单字段映射 多字段映射 映射为其他的对象 映射为 Map 去重 distinct() 过滤 filter() Stream流的其他方法 使用Stream流的弊端 前言 当你某天看…

深度学习模型加密python版本

支持加密的模型: # torch、torch script、onnx、tensorrt 、torch2trt、tensorflow、tensorflow2tensorrt、paddlepaddle、paddle2tensorrt 深度学习推理模型通常以文件的形式进行保存&#xff0c;相应的推理引擎通过读取模型文件并反序列化即可进行推理过程. 这样一来&#…

跨平台Ribbon UI组件QtitanRibbon全新发布v6.7.0——支持Qt 6.6.3

没有Microsoft在其办公解决方案中提供的界面&#xff0c;就无法想象现代应用程序&#xff0c;这个概念称为Ribbon UI&#xff0c;目前它是使应用程序与时俱进的主要属性。QtitanRibbon是一款遵循Microsoft Ribbon UI Paradigm for Qt技术的Ribbon UI组件&#xff0c;QtitanRibb…

vue3【实战】来回拖拽放置图片

效果预览 技术要点 img 标签默认就是可拖拽的&#xff08;a 标签也是&#xff09;事件 e 内的 dataTransfer 对象可用于临时存储事件过程中的数据拖拽事件的默认行为是用浏览器新开页签打开被拖拽对象&#xff0c;所以通常需要禁用默认的浏览器行为被拖拽元素必须设置 id&#…

拉曼光谱入门:2.拉曼光谱发展史、拉曼效应与试样温度的确定方法

1.拉曼光谱技术发展史 这里用简单的箭头与关键字来概括一下拉曼光谱技术的发展史 1928年&#xff1a;拉曼效应的发现 → 拉曼光谱术的初步应用20世纪40年代&#xff1a;红外光谱术的发展 → 拉曼光谱术的限制20世纪60年代&#xff1a;激光作为光源的引入 → 拉曼光谱术的性能提…

阿里云人工智能平台PAI部署开源大模型chatglm3之失败记录

想学习怎么部署大模型&#xff0c;跟着网上的帖子部署了一个星期&#xff0c;然而没有成功。失败的经历也是经历&#xff0c;记在这里。 我一共创建了3个实例来部署chatglm3&#xff0c;每个实例都是基于V100创建的&#xff08;当时没有A10可选了&#xff09;&#xff0c;其显…

数据库缓存管理

1. 简介 缓存管理器是数据库管理系统&#xff08;DBMS&#xff09;中负责管理内存中page并处理文件和索引管理器的page请求的组件。由于内存空间有限&#xff0c;我们不能将所有page存储在缓存池中。因此&#xff0c;缓存管理器需要制定替换策略&#xff0c;当空间填满时选择哪…