1.前言
第一次接触动态规划,不知道具体什么意思,做了题才发现动态规划就是把大问题变成小问题,并解决了小问题重复计算的方法称为动态规划。比如上楼梯,一次上一阶或二阶,求有多少种算法,就可以拆成最后一阶的方法数等于前一阶的方法数加前两阶的方法数,这就是递归算法。但是这样往往会超出时间限制,因为里面有大量的重复,比如一共5阶,F(5)=F(4)+F(3),其中F(4)=F(3)+F(2),这里面F(3)就被重复计算了,这时我们需要将算好的值储存下来,避免重复计算,这就是记忆递归算法。
递归是一种程序的实现方式:函数的自我调用。
动态规划:是一种解决问 题的思想,大规模问题的结果,是由小规模问 题的结果运算得来的。动态规划可用递归来实现(Memorization Search)
使用场景
满足两个条件
-
满足以下条件之一
- 求最大/最小值(Maximum/Minimum )
- 求是否可行(Yes/No )
- 求可行个数(Count(*) )
- 满足不能排序或者交换(Can not sort / swap )
2.实战
2.1第70题
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
心得:很经典的题目,用动态规划,之前一直有个疑问就是,递归的顺序是怎么执行的,是同时计算同一层的两个F(n-1)和F(n-2),还是先计算位于前面的F(n-1),直到算出F(n-1)再计算F(n-2),这次我直接打印出来了,发现是先递归计算出位于前面的F(n-1),这时该储存的已经储存好了,后面计算F(n-2)时就不会重复计算了。
改成自下而上dp(动态规划)
python
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n==1:
return 1
elif n==2:
return 2
dp = [0]*(n+1)
dp[1] = 1
dp[2] = 2
for i in range(3,n+1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
因为该问题符合斐波那契数列,直接算
python
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
a = b = 1
for i in range(2, n + 1):
a, b = b, a + b
return b
2.2第118题
给定一个非负整数 numRows
, 生成「杨辉三角」的前 *numRows
*行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
python
class Solution(object):
def generate(self, numRows):
"""
:type numRows: int
:rtype: List[List[int]]
"""
if numRows==1:
return [[1]]
result = [[1]]
for i in range(2,numRows+1):
current = [1]*i
if i>2:
for j in range(1,i-1):
current[j] = result[i-2][j-1]+result[i-2][j]
result.append(current)
return result
2.3第198题
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你不触动警报装置的情况下,一夜之内能够偷窃到的最高金额。
心得:看到这种求最大金额的题目就要想到动态规划,动态规划就是要把大问题分为一个个的小问题来进行解决。这道题就是,可以把最高金额的问题分为求局部最高金额的问题,然后再递归就能解决了。感觉像是上楼梯的升级题目,多了一个max判断。自左往右。也可以使用递归,自右往左。
python
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums) == 1:
return nums[0]
elif len(nums) == 2:
return max(nums[0], nums[1])
dp = [0]*(len(nums)+1)
dp[1] = nums[0]
dp[2] = nums[1]
for i in range(3,len(nums)+1):
dp[i] = max(dp[i-3] + nums[i-1], dp[i-2] + nums[i-1])
return max(dp[-1], dp[-2])