LeetCode初级算法的Python实现--动态规划
动态规划的本质是递归;所以做题之前一定要会递归;递归式就是状态转移方程;这里将会介绍使用动态规划做题的思维方式。
统一的做题步骤:
1、用递归的方式写出代码;(此方法写的代码在leetcode中一定会超时)
2、找冗余,去冗余;
3、找边界;
1、爬楼梯
假设你正在爬楼梯。需要 n 步你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.1 步 + 1 步
2.2 步
写递归
通常情况下,我们会将问题从大到小处理,也就是这里如果有n个台阶,先处理第n个台阶,然后处理n-1,n-2;所以在这里,总体思路是:第n个台阶可以走1步,也可以走两步,当走第一步时,n-1个台阶又可以分为n-1和n-2,不断递归,所以可写为recursionClimbStairs(n - 1),当n台阶走2步时,recursionClimbStairs(n - 2),然后将两种情况相加;示意图如下图所示:
递归代码如下:
def recursionClimbStairs(self, n):
if n <= 2:
return n
return self.recursionClimbStairs(n - 1) + self.recursionClimbStairs(n - 2)
去冗余:
从上图可知,左下角的n-2和右边的n-2重复了,都进行了计算,所以严重拉长的时间;所以,我们可以把计算了的存起来;首先定义数组nums,当n为1时,方法只有一种,当n为2时,方法有两种,所以nums的前两个值分别为1、2;然后从2到n开始循环,当前值为把上面的递归抄下来即可,就是把方法名改成nums,因为存起来了;所以,数组最后的那个值就是最后的答案;如果不理解,仔细把下面几道题按照这种思虑去写,多写几次就理解了。
找边界
因为循环中有n-2,所以n<=2的情况都需要在循环前写好;
def climbStairs(self, n):
nums = [1, 2]
if n <= 2:
return n
for i in range(2, n):
nums.append(nums[i - 1] + nums[i - 2])
return nums[len(nums) - 1]
2、买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
写递归
从最后第n个数开始,第n个数减去前n-1个数的最小值为当前递归层的最大利益,然后将每层的最大利益再去较大值;代码如下
递归代码如下:
def recursionMaxProfix(self, prices):
if len(prices) < 2:
return 0
return max(prices[- 1] - min(prices[:- 1]),
self.recursionMaxProfix(prices[:- 1]))
去冗余:
前1个数利益为0,这里result用来存结果,转换方法和上面那个例子一样,但是其实如果直接使用上面的递归转换的代码为max(prices[i] - min(prices[:i]), result[i - 1]),但是由于min(prices[:i])又是一层循环所以会导致时间又超时,所以这里可以优化为从第一个数开始就获取最小的值存起来,如下代码所示;
找边界
当列表的数值小于2个时,结果只可能为0;
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
result = [0]
if len(prices) < 2:
return 0
minPrice = prices[0]
for i in range(1, len(prices)):
minPrice = min(minPrice, prices[i - 1])
result.append(max(prices[i] - minPrice, result[i - 1]))
return result[-1]
3、最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
写递归
思想:从最后第n-1个数开始,所以列表从右到左开始加,反之也可以,但里面的代码要改,思想不变;
递归代码如下:
def recursionMaxSubArray(self, idx, nums, maxSum):
if idx < 0:
return maxSum
nums[idx] = max(nums[idx], nums[idx + 1] + nums[idx])
maxSum = max(nums[idx], maxSum)
return self.recursionMaxSubArray(idx - 1, nums, maxSum)
去冗余:
递归是从第n个数开始,循环可以从左到右,递归中使用了maxSum变量存储最大值,而在这里循环中可直接使用数组,和上面的例子相似,但是由于这里的nums变量循环的时候没有用到前面的值,所以直接存入nums中,代码如下所示;
找边界
因为循环中有i-1,且第0个数也不需要计算,所以直接从1开始循环即可;
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
for i in range(1, len(nums)):
nums[i] = max(nums[i] + nums[i - 1], nums[i])
return max(nums)
4、打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
写递归
因为必须相隔一个数,且每个数都是非负的,所以情况分为两种,一种从第一个数开始,一种从第二数开始;两种情况分别递归取较大值;从最后第n个数开始,第n个数加上n-2位置的递归和n-1的递归相比取较大值;代码如下
递归代码如下:
def recursionRob(self, idx, nums):
if idx < 0:
return 0
return max(nums[idx] + self.recursionRob(idx - 2, nums), self.recursionRob(idx - 1, nums))
去冗余:
直接将上述的方法名改成数值即可,如下代码所示;
找边界
因为循环中有i-2,所以列表长度为2之前的需要处理;
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
nums[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
nums[i] = max(nums[i] + nums[i - 2], nums[i - 1])
return nums[len(nums) - 1]
LeetCode初级算法的Python实现--动态规划的更多相关文章
- LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他
LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...
- LeetCode初级算法的Python实现--链表
LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...
- LeetCode初级算法的Python实现--字符串
LeetCode初级算法的Python实现--字符串 # 反转字符串 def reverseString(s): return s[::-1] # 颠倒数字 def reverse(x): if x ...
- LeetCode初级算法的Python实现--数组
LeetCode初级算法的Python实现--数组 # -*- coding: utf-8 -*- """ @Created on 2018/6/3 17:06 @aut ...
- LeetCode初级算法--动态规划01:爬楼梯
LeetCode初级算法--动态规划01:爬楼梯 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net ...
- LeetCode初级算法--数组01:只出现一次的数字
LeetCode初级算法--数组01:只出现一次的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...
- LeetCode初级算法--数组02:旋转数组
LeetCode初级算法--数组02:旋转数组 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...
- LeetCode初级算法--字符串01:反转字符串
LeetCode初级算法--字符串01:反转字符串 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...
- LeetCode初级算法--链表01:反转链表
LeetCode初级算法--链表01:反转链表 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...
随机推荐
- 上传附件(图片base64)封装方法
上传附件(图片base64)封装方法 php 上传附件,base64 项目中封装的接口: public function error($msg){ header("Content-type: ...
- GO语言(四)线程通信
package main import "fmt" func fibon(c,quit chan int) { x,y := , for { select { case c < ...
- ZT UML 类与类之间的关系
1.聚合关系是关联关系的一种,是强的关联关系. 2.聚合是整体和部分之间的关系,例如汽车由引擎.轮胎以及其它零件组成. 3.聚合关系也是通过成员变量来实现的.但是,关联关系所涉及的两个类处在同 ...
- 三、基于任务的异步模式(TAP),推荐使用
一.引言 在上两个专题中我为大家介绍.NET 1.0中的APM和.NET 2.0中的EAP,在使用前面两种模式进行异步编程的时候,大家多多少少肯定会感觉到实现起来比较麻烦, 首先我个人觉得,当使用AP ...
- 利用Kali进行WiFi钓鱼测试实战
文中提及的部分技术可能带有一定攻击性,仅供安全学习和教学用途,禁止非法使用.请不要做一只咖啡馆里安静的猥琐大叔. 写在前面 从至少一年前我就一直想在自己跑kali的笔记本上架个钓鱼热点.然而由于网上的 ...
- Django 模型中FileField字段
FileField¶ class FileField([upload_to=None, max_length=100, **options])¶ 一个上传文件的字段. 注意 FileField字段不支 ...
- interaction-oriented architecture - MVC
MVC(Model-View-Controller),它是专门针 对交互系统提出的,所以如果我们要构建一个交互系统,那么我们就可以直接应用MVC模式,然后 在该模式所搭建的场景的启发下去发现Model ...
- Web网站高并发量的解决方案
摘要: 一个小型的网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单.随着互联网业务的不断丰富,网站相 ...
- iOS开发中方法延迟执行的几种方式
概述 项目开发中经常会用到方法的延时调用,下面列举常用的几种实现方式: 1.performSelector 2.NSTimer 3.NSThread线程的sleep 4.GCD 1.performSe ...
- 十、IntelliJ IDEA 中 Project 和 Module 的概念及区别
在 IntelliJ IDEA 中,没有类似于 Eclipse 工作空间(Workspace)的概念,而是提出了Project和Module这两个概念.接下来,就让咱们一起看看 IntelliJ ID ...