动态规划的本质是递归;所以做题之前一定要会递归;递归式就是状态转移方程;这里将会介绍使用动态规划做题的思维方式。

统一的做题步骤:

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实现--动态规划的更多相关文章

  1. LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他

    LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...

  2. LeetCode初级算法的Python实现--链表

    LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...

  3. LeetCode初级算法的Python实现--字符串

    LeetCode初级算法的Python实现--字符串 # 反转字符串 def reverseString(s): return s[::-1] # 颠倒数字 def reverse(x): if x ...

  4. LeetCode初级算法的Python实现--数组

    LeetCode初级算法的Python实现--数组 # -*- coding: utf-8 -*- """ @Created on 2018/6/3 17:06 @aut ...

  5. LeetCode初级算法--动态规划01:爬楼梯

    LeetCode初级算法--动态规划01:爬楼梯 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net ...

  6. LeetCode初级算法--数组01:只出现一次的数字

    LeetCode初级算法--数组01:只出现一次的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...

  7. LeetCode初级算法--数组02:旋转数组

    LeetCode初级算法--数组02:旋转数组 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...

  8. LeetCode初级算法--字符串01:反转字符串

    LeetCode初级算法--字符串01:反转字符串 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...

  9. LeetCode初级算法--链表01:反转链表

    LeetCode初级算法--链表01:反转链表 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/ ...

随机推荐

  1. hashcode方法 简析

    package com.ycgwl; import java.util.HashMap; class People{ private String name; private int age; pub ...

  2. 11G R2 RAC添加监听

    步骤如下: 检查默认network的network number,红色字体1,一会儿添加监听会用到: [grid@rac121 admin]$ srvctl config network Networ ...

  3. January 21 2017 Week 3 Saturday

    Courage is grace under pressure. 勇气就是压力下的优雅. In the face of stress, can you deal with your task smoo ...

  4. WSDM 2014推荐系统论文

    Xiao Yu, Hao Ma, Paul Hsu, Jiawei Han On Building Entity Recommender Systems Using User Click Log an ...

  5. 时间函数应用 time

    表 1. C 时间函数 function 定义 含义 返回值 精度 time() time 函数获得从 1970 年 1 月 1 日 0 点到当前的秒数,存储在time_t结构之中. time_t 秒 ...

  6. 制作炫酷雪花背景的jQuery插件

    插件使用十分简单,代码已经放至我的GitHub,大家可以下载以及使用或者更新改进代码. HTML代码源码: <!DOCTYPE html> <html> <head> ...

  7. UVa 1625 - Color Length(线性DP + 滚动数组)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  8. 关于iOS 3D touch 指纹验证的随笔

    file:///Users/OWen/Desktop/3DTouch.png 随着iOS系统不断的更新迭代,苹果总会推出一些新的功能,今天就研究了一下iOS8之后推出的指纹验证的功能,然后写了一个小d ...

  9. 阿里云云服务器Windows Server 2012 R2无法安装IIS等组件的解决办法

    Windows Server2012 R2数据中心版 不管安装什么组件,都显示存储空间不足,无法应用命令,错误代码0x80070008. 最终确认是服务器配置过低的原因,因为这个型号是低级别的配置,1 ...

  10. 如何不使用 submit 按钮来提交表单?

      如果我们不想用 submit 按钮来提交表单,我们也可以用超链接来提交,我们可以这样写代码: <a href=”javascript: document.myform.submit ();” ...