连续子数组的最大和

  • 动态规划的三大步骤
  • 案例详解-青蛙跳台阶问题(一维DP)
  • 跳台阶扩展问题
  • 斐波那契数列
  • 把数字翻译成字符串
  • 最长不含重复字符的子字符串
  • 案例详解-不同路径(二维数组的DP)
  • 问题描述
  • 连续子数组的最大和(一)
  • 连续子数组的最大和(二)
  • 礼物的最大值

动态规划的三大步骤

动态规划,无非就是利用历史记录,来避免我们的重复计算。而这些历史记录,我们得需要一些变量来保存,一般是用一维数组或者二维数组来保存。
第一步骤:定义数组元素的含义,上面说了,我么会用一个数组,来保存历史数组,假设用一维数组dp[],非常重要的一点,就是规定你这个数组元素的含义,例如你的dp[i]是代表什么意思?
第二步骤:找出数组元素之间的关系式,我觉得动态规划,还有一点类似于我么高中学习时的归纳法,当我们要计算dp[n]时,是可以利用dp[n-1],dp[n-2]…dp[1],来推出dp[n]的,也就是可以利用历史数据来推出新的元素值,所以我么要找出数组元素之间的关系式,例如dp[n]=dp[n-1]+dp[n-2],这个就是他们的关系式了。而这一步,也是最难的一步。

学过动态规划的可能都经常听到最优子结构,吧大的问题拆分成小的问题。

第三步骤:找出初始值。学过数学归纳法的都知道,虽然我么知道了数组元素之间的关系式,例如dp[n]=dp[n-1]+dp[n-2],我么可以通过dp[n-1]和dp[n-2]来计算dp[n],但是,我么得知道初始值,例如一直推下去的话,会由 dp[3] = dp[2] + dp[1]。而 dp[2] 和 dp[1] 是不能再分解的了,所以我们必须要能够直接获得 dp[2] 和 dp[1] 的值,而这,就是所谓的初始值
有了初始值,并且有了数组元素之间的关系式,那么我们就可以得到dp[n]的值了,而dp[n]的含义是由你来定义的,你想求什么,就定义它是什么,这样,这道题也就解出来了。

案例详解-青蛙跳台阶问题(一维DP)

问题描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

(1)定义数组元素的含义
首先我们来定义dp[i]的含义,我么的问题时要求青蛙跳上n级的台阶总共有多少种跳法,那我么定义dp[i]的含义为:跳上一个i级台阶总共有dp[i]种跳法
这样,如果我么可算出dp[n],就是要求的答案。
(2)找出数组元素间的关系式
我么的目的是求dp[n],动态规划的题,就是吧一个规模比较大的问题分成几个规模比较小的问题,然后由小的问题推导出大的问题。也就是说,dp[n]的规模为n,比它规模小的是n-1,n-2,n-3…也就是说,dp[n]一定会和dp[n-1],dp[n-2]…存在某种关系的。我么要找出他们的关系。
对于这道题,由于情况可以选择跳一级,也可以选择跳两级,所以青蛙到达第n级的台阶有两种方式
一种是从第n-1级跳上来
一种是从第n-2级跳上来
由于我么是要算所有可能的跳法的,所以有dp[n]=dp[n-1]+dp[n-2]
(3) 找出初始条件
当 n = 1 时,dp[1] = dp[0] + dp[-1],而我们是数组是不允许下标为负数的,所以对于 dp[1],我们必须要直接给出它的数值,相当于初始值,显然,dp[1] = 1。一样,dp[0] = 0.(因为 0 个台阶,那肯定是 0 种跳法了)。于是得出初始值:
dp[0] = 0.
初始值的严谨性。例如对于上面的题,当 n = 2 时,dp[2] = dp[1] + dp[0] = 1。这显然是错误的,你可以模拟一下,应该是 dp[2] = 2。
也就是说,在寻找初始值的时候,一定要注意不要找漏了,dp[2] 也算是一个初始值,不能通过公式计算得出。

class Solution:def jumpFloor(self,n):if (n<=2)return n#创建一个数组来保存历史数据dp=[]#给出初始值dp[0]=0dp[1]=1#通过关系式来计算dp[n]for i in range(3,n):dp[i]=dp[i-1]+dp[i-2]return dp[n]#吧最终结果返回

跳台阶扩展问题

一只青蛙一次可跳上1级台阶,也可以跳上2级…它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法
数据范围:1<=n<=20
进阶:空间复杂度O(1),时间复杂度O(1)

解法:
方法一:斐波那切数列
f(n) = f(n-1)+f(n-2)+f(n-3)+…f(1)
f(n-1)= f(n-2)+f(n-3)+…f(1)
f(n) = 2*f(n-1) n>1
方法二:找规律
number = 1, 1种
number = 2, 2种
number = 3, 4种
number = 4, 8种

number = n, 2^(n-1)种

class Solution:def jumpFloorII(self,number):if number==1:return 1fN=1fone=1for i in range(2,number+1):fN=2*fonefone=fNreturn fN
class Solution2:def jumpFloorII(self,number):if number==1:return 1dp=[]for i in range(2,number)dp[i]=2*dp[i-1]return dp

斐波那契数列

class Solution:def Fibonacci(self,n):if n<=0:return 0a=b=1for i in range(2,n):a,b=b,a+breturn b

把数字翻译成字符串


解法:动态规划,类似跳台阶同类问题
有一种将字母编码成数字的方式:‘a’->1, ‘b->2’, … , ‘z->26’。

我们把一个字符串编码成一串数字,再考虑逆向编译成字符串。

由于没有分隔符,数字编码成字母可能有多种编译结果,例如 11 既可以看做是两个 ‘a’ 也可以看做是一个 ‘k’ 。但 10 只可能是 ‘j’ ,因为 0 不能编译成任何结果。

现在给一串数字,返回有多少种可能的译码结果

在动态规划中,用dp[i]=dp[i-1]+dp[i-2]来解决两个编码分支的问题,判别条件则是数字范围是否在11到26之间。

class Solution:def solve(self,nums):if nums=='0':return 0if nums=='10' or nums=='20':return 1if nums[0]=='0':return 0for i in range(1,len(nums)):if nums[i]=='0' and (nums[i-1]!='1' and nums[i-1]!='2'):return 0dp=[1 for _ in range(len(nums)+1)]for i in range(2,len(nums)+1):if (nums[i-2]=='1' and nums[i-1]!='0') or \(nums[i-2]=='2' and (nums[i-1]>'0' and nums[i-1]<'7')):dp[i]=dp[i-1]+dp[i-2]else:dp[i]=dp[i-1]return dp[len(nums)]
if __name__ == '__main__':nums='12258's=Solution()print(s.solve(nums))#5

最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度

分析:


空间复杂度优化:
由于返回值是取 dpdp 列表最大值,因此可借助变量 tmptmp 存储 dp[j]dp[j] ,变量 resres 每轮更新最大值即可。
此优化可节省 dpdp 列表使用的 O(N)O(N) 大小的额外空间。

观察转移方程,可知问题为:每轮遍历字符 s[j]s[j] 时,如何计算索引 ii ?
以下介绍 哈希表方法。

方法一:动态规划 + 哈希表
哈希表统计: 遍历字符串 ss 时,使用哈希表(记为 dicdic )统计 各字符最后一次出现的索引位置 。
左边界 ii 获取方式: 遍历到 s[j]s[j] 时,可通过访问哈希表 dic[s[j]]dic[s[j]] 获取最近的相同字符的索引 ii 。
复杂度分析:
时间复杂度 O(N)O(N) : 其中 NN 为字符串长度,动态规划需遍历计算 dpdp 列表。
空间复杂度 O(1)O(1) : 字符的 ASCII 码范围为 00 ~ 127127 ,哈希表 dicdic 最多使用 O(128) = O(1)O(128)=O(1) 大小的额外空间。

class Solution:def lengthOfLongestSubstring(self, s: str) -> int:dic = {}res = tmp = 0for j in range(len(s)):i = dic.get(s[j], -1) # 获取索引 idic[s[j]] = j # 更新哈希表tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]res = max(res, tmp) # max(dp[j - 1], dp[j])return res

案例详解-不同路径(二维数组的DP)

DP的算法题,可以说,80%都要用二维数组的,下面这道题以二维数组为主

问题描述

一个机器人位于一个mxn网格的左上角(起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?

例如,上图是一个7x3的网格。有多少可能的路径
说明:m和n的值均不超过100
依然是三个步骤来解决:
步骤一、定义数组元素的含义
由于我们的目的是从左上角到右下角一共有多少种路径,那么我们就定义dp[i][j]的含义为:当机器人从左上角走到(i,j)这个位置时,一共有dp[i][j]种路径。那么,dp[m-1][n-1]就是我么要的答案了。

注意,这个网络相当于一个二维数组,数组是从下标为0开始算起的,所以右下角的位置是(m-1,n-1),所以dp[m-1][n-1]就是我们要计算的答案。

步骤二:找出关系数组元素间的关系式
想象以下,机器人要怎么样才能到达 (i, j) 这个位置?由于机器人可以向下走或者向右走,所以有两种方式到达:
一种是,从(i-1,j)这个位置走一步到达
一种是,从(i,j-1)这个位置走一步到达
因为是计算所有可能的步骤,所以是把所有可能走的路径都加起来,所以关系式dp[i][j]=dp[j-1][j]+dp[i][j-1]
步骤三:找出初始值
显然,当 dp[i] [j] 中,如果 i 或者 j 有一个为 0,那么还能使用关系式吗?答是不能的,因为这个时候把 i - 1 或者 j - 1,就变成负数了,数组就会出问题了,所以我们的初始值是计算出所有的 dp[0] [0….n-1] 和所有的 dp[0….m-1] [0]。这个还是非常容易计算的,相当于计算机图中的最上面一行和左边一列。因此初始值如下:
dp[0][0…n-1]=1#相当于最上面一行,机器人只能一直往右走
dp[0…m-1] [0] = 1; // 相当于最左面一列,机器人只能一直往下走

class Solution:def uniquePaths(self, m, n):""":type m: int:type n: int:rtype: int"""# dp[i][j]表示到第i行j列为止总共有多少条不同的路径dp = [[1 for _ in range(n)] for _ in range(m)]for i in range(1, m):for j in range(1, n):# 递推公式dp[i][j] = dp[i - 1][j] + dp[i][j - 1]return dp[-1][-1]

O(n*m) 的空间复杂度可以优化成 O(min(n, m)) 的空间复杂度的

排列组合
这也是一个组合问题,因为机器人一定会走m+n-2步,即从m+n-2中挑出m-1步向下走。问题转化为计算C(m+n-2,m-1),时间复杂度为O(n),空间复杂度O(1)。

class Solution:def uniquePaths(self, m, n):""":type m: int:type n: int:rtype: int"""# C^(m-1)_(m+n-2)res = 1for i in range(m, m+n-1):res *= ires /= i-m+1return int(res)

连续子数组的最大和(一)

题目:
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求:时间复杂度为O(n),空间复杂度为O(n)
进阶:时间复杂度为O(n),空间复杂度为O(1)

方法一:动态规划

复杂度
时间复杂度:O(n)O(n),其中 nn 为 \textit{nums}nums 数组的长度。我们只需要遍历一遍数组即可求得答案。
空间复杂度:O(1)O(1)。我们只需要常数空间存放若干变量。

class Solution:def maxSubArray(self,nums):for i,num in enumerate(nums[1:]):nums[i+1]=num if num>num+nums[i] else num+nums[i]return max(nums)

连续子数组的最大和(二)

题目:
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,找到一个具有最大和的连续子数组。
1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
2.如果存在多个最大和的连续子数组,那么返回其中长度最长的,该题数据保证这个最长的只存在一个
3.该题定义的子数组的最小长度为1,不存在为空的子数组,即不存在[]是某个数组的子数组
4.返回的数组不计入空间复杂度计算
要求:时间复杂度O(n),空间复杂度O(n)
进阶:时间复杂度O(n),空间复杂度O(1)

class Solution:def FindGreatestSumOfSubArray(self,array):maxval=array[0]temp=array[0]endindex=1beginindex=0for i in range(1,len(array)):if temp<0:temp=array[i]beginindex=ielse:temp+=array[i]if temp>=maxval:endindex=imaxval=tempif beginindex>endindex:return array[endindex:endindex+1]return array[beginindex:endindex+1]

礼物的最大值

在一个mxn的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值>0)。你可以从棋盘的左上角开始拿格子的礼物,并每次向右或向下移动一格,直到到达棋盘的右下角。给定一个棋盘及其上门的礼物的价值,请计算你最多能拿到多少价值的礼物?

在动态规划求解这问题的时候,我们找出到达每一行中每个位置的最大值,在求解第一行的时候,很明显只能一直向右走,对于第二行的一个数字,很明显只能一直向右走,对于第二行的一个数字,很明显只能从(0,0)走到(0,1),这个还是先用与原始矩阵同样大的矩阵进行分析,

class Solution:def getmaxValue(self,values,rows,cols):if not values or rows<=0 or cols<=0:return 0#用于存放中间数值的临时数组temp=[0]*colsfor i in range(rows):for j in range(cols):left=0up=0if i >0:up=temp[j]if j>0:left=temp[j-1]temp[j]=max(up,left)+values[i*rows+j]return temp[-1]

动态规划-python相关推荐

  1. leetcode动态规划(python与c++)

    1 . 斐波那契数 class Solution:def fib(self, n: int) -> int:# if n==0:# return 0# elif n==1:# return 1# ...

  2. python购买股票_动态规划python实现-买股票的最佳时机

    买股票的最佳时机(动态规划python实现) 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大 ...

  3. 每日一道算法题--leetcode 509--斐波那契数(动态规划)--python

    [题目描述] [代码思路] 自底向上的动态规划,避免了采用递归浪费空间以及重复计算. [源代码] class Solution(object):def fib(self, N):"" ...

  4. leetcode解码方法(动态规划python)

    描述 有一个消息包含A-Z通过以下规则编码 'A' -> 1 'B' -> 2 - 'Z' -> 26 现在给你一个加密过后的消息,问有几种解码的方式 我们不能解码空串,因此若消息为 ...

  5. 京东8.27算法笔试-滚雪球(动态规划python)

    小球从上向下滚,每次只可以滚到左下,下,右下(滚到一个格子里面,把值做和).计算小球滚到最下一层的最大值.如下: 动态规划代码如下: def method(nums):if nums==0:retur ...

  6. 动态规划( python)

    动态规划的三要素:最优子结构,边界和状态转移函数,最优子结构是指每个阶段的最优状态可以从之前某个阶段的某个或某些状态直接得到(子问题的最优解能够决定这个问题的最优解),边界指的是问题最小子集的解(初始 ...

  7. 贝尔曼方程动态规划python,【强化学习】马尔科夫决策过程之Bellman Equation(贝尔曼方程)...

    前面总结了马尔科夫决策过程之Markov Processes(马尔科夫过程),见下文:马尔科夫决策过程之Markov Processes(马尔科夫过程) 马尔科夫决策过程之Markov Reward ...

  8. leetcode最大矩形 (动态规划 python)

    描述 给你一个二维矩阵,权值为False和True,找到一个最大的矩形,使得里面的值全部为True,输出它的面积 您在真实的面试中是否遇到过这个题? 样例 样例1 输入: [ [1, 1, 0, 0, ...

  9. 最小编辑距离 动态规划 python

    m和n的两个字符串,设有以下几种操作:替换(R),插入(I)和删除(D)且都是相同的操作.求转换一个字符串到另一个需要的最少操作数量.这个数量就可以被视为最小编辑距离.如:acd与ace的Editio ...

最新文章

  1. Ubuntu 系统自带的截图工具screenshot
  2. Java基于对象基础 基于对象和面向对象的区别(转)
  3. Android--Retrofit的简单使用(一)
  4. 背口诀14天精通c语言pdf下载,C语言必背18个经典程序
  5. nodejs 获取文件夹中所有文件、图片 名
  6. 一个对象的属性_【前端冷知识】如何判断一个对象的某个属性是可写的?
  7. spring mvc静态资源访问的配置
  8. java中审核订单流程图_Java 后端横扫阿里、滴滴、美团总结的面试经验!
  9. windows下安装和设置gradle
  10. python中isort的使用
  11. python flask框架下登录注册界面_Python的Flask框架中实现简单的登录功能的教程
  12. 如何配置IIS日志信息
  13. ubuntu终端连接远程计算机
  14. filezilla 设置服务器_MC云服务器搭建教程[非硬核]
  15. Atitit 高级人员的指标 参照发达国家(Developed Country)指标 目录 1. 普遍特征是较高的发展指数、人均生产总值、工程化水准和品质 [1]  。科学技术水准等指标 1 2.
  16. C标准库函数中复杂的函数声明
  17. 红巨星粒子插件Trapcode Suite 14.0 Win版全套中文完美汉化版
  18. 2022-2028年中国光纤放大器行业市场发展潜力及投资策略研究报告
  19. HTML5游子吟网页的完整代码,《游子吟》教学案
  20. 关于网站被挂马的症状以及处理解决方法

热门文章

  1. 字符与字节之间有什么区别?
  2. 用Python通过用户cookies访问微博首页
  3. PL/SQL developer的下载、安装、使用、破解,亲自测试。安全使用。
  4. QCon北京2015报名火爆,4月8日提前停止售票
  5. 从零开始手搓一个STM32与机智云的小项目——硬件介绍
  6. java计算机毕业设计基于ssm社会保险养老系统
  7. AJAX:实现局部刷新
  8. 详解php://filter以及死亡绕过
  9. STM32的独立看门狗
  10. Python内置模块