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/ ...
随机推荐
- centos无法用password登录,只能用public key的解决办法
如上图只能用public key登录,只是我在17年申请的阿里云免费体验半年的服务器上遇到的, 那么我们用阿里云后台的远程连接按钮进入服务器,进入后 就看/etc/ssh/sshd_config文件配 ...
- Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等
本课主题 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 Spark Worke ...
- Hibernate多对多关联关系
今天遇到一个问题:有一个的类Reckoning,一个类AccountItem.这两个类之间的关系时多对多的关联关系. 一开始是由AccountItem来维护关联关系的,也就是Reckoning.hbm ...
- Ajax回退刷新页面问题的解决办法
在脚本之家看到一篇文章,觉得以后可能会用上,但是竟然不能收藏,所以只能将其转到博客园. 以下是原文地址: http://www.jb51.net/article/87856.htm 这篇文章主要介 ...
- 阿里云maven仓库镜像mirror,速度超快
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http:/ ...
- UVa 247 - Calling Circles(Floyd求有向图的传递闭包)
链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- 【[ZJOI2006]物流运输】
一直不会做,觉得这是一道神题 于是万般无奈下去借鉴抄了一下题解 发现这就是一道套路题 我们用\(dp[i]\)表示前\(i\)天的最小总花费,于是我们就可以用一个常规的老套路来做了 那就是枚举断点 我 ...
- es6之proxy和reflect
一.proxy //Proxy和Reflect //供应商 let obj={ time:"2017-11-21", name:"net", _r:123 } ...
- Spring知识概括梳理
1. Spring 容器 http://blog.csdn.net/chenssy/article/details/8188570 2. Spring 注解 1)@Autowired http://b ...
- 二十八、详述 IntelliJ IDEA 远程调试 Tomcat 的方法
在调试代码的过程中,为了更好的定位及解决问题,有时候需要我们使用远程调试的方法.在本文中,就让我们一起来看看,如何利用 IntelliJ IDEA 进行远程 Tomcat 的调试. 首先,配置remo ...