python算法与数据结构---动态规划

动态规划

记不住过去的人,注定要重蹈覆辙。

定义

对于一个模型为n的问题,将其分解为k个规模较小的子问题(阶段),按顺序求解子问题,前一子问题的解,为后一子问题提供有用的信息。在求解任一子问题时,通过决策求得局部最优解,依次解决各子问题。最后通过简单的判断,得到原问题的解。

经典案例—斐波那契数列

斐波那契数列又称黄金分割数列。因数学家莱昂纳多-斐波那契以兔子繁殖为例引入,故又称兔子数列。

1, 1, 2, 3, 5, 8, 13, 21...

在数学上满足递推的方法定义:

F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2)  (n>=2)
def fib(n):
	if n <= 0:
		return 0
	if n == 1:
		return 1
	return fib(n-1) + fib(n-2)

在这里插入图片描述
分析:
上图中的二叉树的每个子节点都需要执行一次,如果n= 6,则需要再向下延申,fib(2)就需要执行5次。每次调用时都需要保留上下文,在时间和空间上开销很大。那如果我们把每次计算的结果保存起来,下次用到的时候直接通过查表得方式调用,就可以节省大量得时间,这就是动态规划得基本思想。

动态规划解决

def fib_dp(n):
	#定义一个dp数组,记录每个n的值,这里n+1长度的便于写代码
	dp = [-1] * (n+1)
	#初始化
	dp[1] = dp[2] = 1
	for i in range(3, n+1):
		dp[i] = dp[i-1] + dp[i-2]
	return dp[n]

解题步骤

核心思想是递推,难点在于dp[i]状态代表什么,然后构造转移矩阵,利用初始条件递推出最终结果。
解题步骤:

  1. 划分阶段:按照问题的时间和空间特征,把若干问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要有序或者是可排序的,否则问题就无法求解。
  2. 确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
  3. 确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就根据上一阶段的状态和决策来导出本阶段的状态。所以确定了决策,状态转移方程也就可写出。但事实上常常是反过来的,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。
  4. 寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

动态规划算法的性质

动态规划的要素:问题的最优解由相关子问题的最优解组合而成,并且可以独立求解子问题(最优子结构)。

  • (1)最优化原理:如果问题的最优解包含的子问题也是最优的,就称该问题具有最优子结构,即满足最优化原理;
  • (2)无后效性:即某阶段状态(定义的新子问题)一旦确定,就不受这个状态以后决策的影响,也就是说,某状态以后的过程不会影响以前的状态,只与其以前的状态有关。

LeetCode例题

62不同路径

https://leetcode.cn/problems/unique-paths/description/
在这里插入图片描述
思路:
每一步只能从向下或向右移动一步,所以对于坐标(i,j)要么从(i-1,j)过来(向下走一步),要么从(i,j-1)过来(向右走一步)。

状态定义:
dp(i, j)表示从左上角走到(i,j)的路径数量

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        #定义dp数组,用dp(i,j)表示从左上角走到(i,j)的路径数量dp(i,j)
        dp = [[0] * n for _ in range(m)]

        # 初始化dp数组,第一行和第一列、应该都是1,都只有一种情况,从左边或者上边过来
        dp[0][0] = 1
        for i in range(m):
            dp[i][0] = 1
        for j in range(n):
            dp[0][j] = 1
        
        #print(dp) # 可以看下dp  [[1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0]]
        #计算剩余位置,填充好dp数组
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        print(dp)  # [[1, 1, 1, 1, 1, 1, 1], [1, 2, 3, 4, 5, 6, 7], [1, 3, 6, 10, 15, 21, 28]]
        ## 通过查表的方式,返回最终结果
        return dp[m-1][n-1]

LCR 099. 最小路径和

https://leetcode.cn/problems/0i0mDW/description/
在这里插入图片描述
思路:
与上一题类似,对于坐标(i,j)要么从(i-1,j)过来(向下走一步),要么从(i,j-1)过来(向右走一步),但是加了条件,每个坐标上的值有了意义,需要进行累加处理。

状态:

设dp为大小m*n的矩阵,其中dp(i,j)的值代表直到走到(i,j)的最小路径和。

转移方程:

  1. 当可以从左边和上面过来,即左边和上边都不是矩阵边界时:
    dp(i, j) = grid(i, j) + min(dp(i-1, j), dp(i, j-1))
    
  2. 当只能从上边过来,即左边是矩阵边界时:
    dp(i, j) = grid(i, j ) + dp(i, j-1)
    
  3. 当只能从左边过来,即上边是矩阵边界时(i=0)
    dp(i, j) = grid(i, j) + dp(i, j-1)
    
  4. 在起点时(i=0, j=0)
    dp(i, j) = grid(i, j)
    
class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        rows = len(grid)
        cols = len(grid[0])

        #其中dp(i, j)的值代表直到走到(i,j)的最小路径和
        dp = [[0] * cols for _ in range(rows)]

        for i in range(rows):
            for j in range(cols):
                #起点
                if i == 0 and j == 0:
                    dp[i][j] = grid[i][j]
                # 中间的点,可以从左边和上边过来
                elif i != 0 and j != 0:
                    dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
                #只能从左边过来
                elif i == 0 and j != 0:
                    dp[i][j] = grid[i][j] + dp[i][j-1]
                #只能从上边过来
                elif i != 0 and j == 0:
                    dp[i][j] = grid[i][j] + dp[i-1][j]
        #print(dp) # grid =[[1,3,1],[1,5,1],[4,2,1]]
        return dp[rows-1][cols-1]

1884. 鸡蛋掉落-两枚鸡蛋

https://leetcode.cn/problems/egg-drop-with-2-eggs-and-n-floors/description/
在这里插入图片描述
思路:

开始有两枚鸡蛋,所以要分情况讨论,还剩两枚鸡蛋,和一枚鸡蛋;

  • 1、如果只有一枚鸡蛋:此时我们需要从1层逐层校验,才能获得确切的值,
  • 2、如果有两枚鸡蛋:第一次操作可以在任意一层,如果在k层丢下时碎了一个,那问题就转换成了第一点。

状态:

dp(i, j)表示有 i+1 鸡蛋时,验证 j 层楼需要的最少操作次数,我们可以分开分析 i = 0 和 i = 1的情况:

  • ·i = 0 时(只有一枚鸡蛋了):
    需要逐层检验,当在 j 层楼时,则dp(0, j) = j

  • i = 1时:

    • (1)假设当前在k层的时候第一枚鸡蛋碎了,那么问题就转换成了dp(0, k-1),总共的操作次数是,dp(0, k-1) + 1;

    • (2)如果当前在k层丢下鸡蛋,没有碎,此时可以证明在k层的时候鸡蛋不会碎,那么问题就转化成dp(1, j-k),总共的操作次数是dp(1, j-k) + 1

    • 基于(1)(2)取最坏情况:

      max(dp(0, k-1), dp(1, j-k) + 1)

    • 综上,

      dp(1, j) = min(dp(1, j), max(dp(0, k-1), dp(1, j-k) + 1))

转移方程:

dp(0, j) = j, i=0
dp(1, j) = min(dp(1, j), max(dp(1, j), max(dp(0, k-1), dp(1, j-k) + 1))), i=1

class Solution:
    def twoEggDrop(self, n: int) -> int:
        # dp(i, j)表示有i+1枚鸡蛋时,验证j层楼需要的最少操作次数
        dp = [[sys.maxsize] * (n + 1) for _ in range(2)]

        #初始化dp数组
        dp[0][0] = dp[1][0] = 0 
        
        #初始化,只有一枚鸡蛋的情况
        for j in range(n+1):
            dp[0][j] = j
        
        for j in range(n+1):
            #两枚鸡蛋时,在k层是否碎了,分情况讨论
             for k in range(j + 1):
                 dp[1][j] = min(dp[1][j], max(dp[0][k-1] + 1, dp[1][j-k] + 1))

        # 查表返回最终结果
        return dp[1][n]

附录基础

python数据结构与算法理论基础(专栏)

数据结构与算法(python)http://t.csdnimg.cn/Gb6MN

程序 = 数据结构 + 算法;而且在面试过程中这些是必考,必问的内容。内容大纲:基础数据结构(树、链表、栈、队列等)、常见算法(排序算法、递归算法等)。

专栏是基于python的基础知识,是很好的入门学习资料。帮助大家快速理解这些数据结构和常见算法的概念,同时结合力扣题目,也能更好的掌握这些知识,达到在面试中游刃有余的效果。

python基础语法

python基础精讲 http://t.csdnimg.cn/HdKdi

本专栏主要针对python基础语法,帮助学习者快速接触并掌握python大部分最重要的语法特征。
1、基本数据类型和变量
2、分支结构与循环结构
3、函数与异常处理
4、类与模块
5、文件读写
通过本专栏可以快速掌握python的基础语法。

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

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

相关文章

【MySQL】- 09 Select Count

【MySQL】- 09 Select Count 1认识COUNT2 COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别3 COUNT(*)的优化 4 COUNT(*)和COUNT(1)5 COUNT(字段)总结 数据库查询相信很多人都不陌生&#xff0c;所有经常有人调侃程序员就是CRUD专员&#xff0c;这所谓的CRUD指的就是数据库的增删…

产业热点 | 从 Vision Pro 发售,洞见空间计算时代新机遇

*图源&#xff1a;Apple 官网 近日首批 Vision Pro 启动预约发售&#xff0c;短短一周就预估售出 20 万台&#xff0c;如今正式发售在即&#xff0c;再度受到各界的热切关注。 *图源&#xff1a;Apple 官网 同样作为空间计算赛道企业&#xff0c;ALVA Systems 在过去十余年始…

IP数据云识别真实IP与虚假流量案例

随着互联网的普及&#xff0c;企业在数字领域面临着越来越复杂的网络威胁。为了保护网站免受虚假流量和恶意攻击的影响&#xff0c;许多企业正在采用IP数据云。本文将结合一个真实案例&#xff0c;深入探讨IP数据云如何成功准确地识别真实用户IP和虚假流量IP&#xff0c;提高网…

ESU毅速丨3D打印技术引领模具制造创新革命

随着科技的飞速发展&#xff0c;3D打印技术已经成为制造业的新宠。而在模具制造领域&#xff0c;3D打印技术更是带来了巨大的创新价值&#xff0c;引领着模具制造的革命性变革。 传统模具制造过程中&#xff0c;需要经过多道繁琐工序&#xff0c;而3D打印技术简化了这一过程。3…

python接口自动化(五)--接口测试用例和接口测试报告模板(详解)

简介 当今社会在测试领域&#xff0c;接口测试已经越来越多的被提及&#xff0c;被重视&#xff0c;而且现在好多招聘信息要对接口测试提出要求。区别于传统意义上的系统级别测试&#xff0c;很多测试人员在接触到接口测试的时候&#xff0c;也许对测试执行还可以比较顺利的上手…

基于场景文字知识挖掘的细粒度图像识别算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;基于场景文字知识挖掘的细粒度图像识别算法1、研究背景2、方法提出方法模块 3、试验4、文章贡献 二、RNN代码学习2.1、什么是RNN2…

day43_jdbc

今日内容 0 复习昨日 1 SQL注入问题 2 PreparedStatement 3 完成CRUD练习 4 ORM 5 DBUtil (properties) 6 事务操作 0 复习昨日 已经找人提问… 1 SQL注入 1.1 什么是SQL注入 用户输入的数据中有SQL关键词,导致在执行SQL语句时出现一些不正常的情况.这就是SQL注入! 出现SQL注入…

两种方式实现文本超出指定行数显示展开收起...

需要实现这样一个功能 默认高度下文本超出隐藏&#xff0c;点击展开可查看所有内容&#xff0c;点击收起可折叠 方法一&#xff1a;通过html和css实现 代码部分 html:<div className"expand-fold"><input id"check-box" type"checkbox&qu…

幻兽帕鲁游戏中走路卡顿并且会出现回弹是什么原因?

可能原因是最近的 1.4.0 更新后&#xff0c;代码中有一个启动参数的加入&#xff0c;导致 CPU 占用极高。 可以远程连接你的服务器 然后执行下面的代码&#xff0c;删除代码中的那个启动参数。 # 删除可能导致人物回弹的游戏服务器启动参数 sudo -u ecs-assist-user sed -i s…

ios搭建OpenGL环境

前言 本篇文章介绍在ios搭建OpenGL开发环境 在app的启动文章中&#xff0c;讲述了一个ios应用是如何启动的以及在IOS 13之后苹果公司推出的多窗口功能&#xff0c;通过app的启动这篇文章&#xff0c;我们基本能随心所欲的搭建一个app应用环境&#xff0c;搭建完成后的基本文件…

雨课堂怎么搜答案?七个受欢迎的搜题分享了 #微信#职场发展雨课堂怎么搜答案?七个受欢迎的搜题分享了 #微信#职场发展

积极参加社团活动和实践项目&#xff0c;可以帮助大学生拓宽人脉圈和锻炼实际操作能力。 1.福昕翻译 可以一键翻译文档内容&#xff0c;并提供还原排版的译文&#xff0c;对经常看外文文献的朋友来说&#xff0c;绝对是福音 福昕翻译是一流专业的在线翻译服务平台,支持PDF文…

一文带你了解编码集

编码集 1. ASCII编码&#xff1a; 127个字母 8个数据位足够存储字母、数字、符号&#xff0c;支持到0x7F。 2. GB2312编码 每个汉字占据2个字节(高位和低位)&#xff0c;16个数据。GB2312是对ASCII的中文扩展&#xff0c;共包含7000多个汉字。是计算机发展到中国后发展起来…

Python算法100例-1.3 牛顿迭代法求方程根

完整源代码项目地址&#xff0c;关注博主私信’源代码’后可获取 1&#xff0e;问题描述 编写用牛顿迭代法求方程根的函数。方程为 a x 3 b x 2 c x d 0 ax^3bx^2cxd0 ax3bx2cxd0&#xff0c;系数a、b、c、d由主函数输入&#xff0c;求x在1附近的一个实根。求出根后&…

VBA字典与数组第十一讲:普通公式与数组公式的本质区别

《VBA数组与字典方案》教程&#xff08;10144533&#xff09;是我推出的第三套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;字典是VBA的精华&#xff0c;我要求学员必学。7.1.3.9教程和手册掌握后&#xff0c;可以解决大多数工作中遇到的实际问题。…

MAE实战:使用MAE提高主干网络的精度(一)

摘要 MAE已经出来有几年了&#xff0c;很多人还不知道怎么去使用&#xff0c;本文通过两个例子说明一下。分两部分&#xff0c;一部分介绍一个简单的例子&#xff0c;让大家了解MAE训练的流程。一部分是一个新的模型&#xff0c;让大家了解如何将自己的模型加入MAE。 论文标…

Java 获取操作时区 ZonedDateTime

Java 获取操作时区 ZonedDateTime package com.zhong.timeaddress;import java.time.Clock; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Set;public class TimeAddress {public static void main(String[] args) {// 获取系统默认时区ZoneId…

PyTorch 中神经网络库torch.nn的详细介绍

1. torch.nn torch.nn 是 PyTorch 深度学习框架中的一个核心模块&#xff0c;它为构建和训练神经网络提供了丰富的类库。 以下是 torch.nn 的关键组成部分及其功能&#xff1a; nn.Module 类&#xff1a; nn.Module 是所有自定义神经网络模型的基类。用户通常会从这个类派生…

前端工程化之:webpack2-2(内置插件)

目录 一、内置插件 1.DefinePlugin 2.BannerPlugin 3.ProvidePlugin 一、内置插件 所有的 webpack 内置插件都作为 webpack 的静态属性存在的&#xff0c;使用下面的方式即可创建一个插件对象&#xff1a; const webpack require("webpack")new webpack.插件…

计算机设计大赛 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …