第12天 动态规划
70.爬楼梯
1.当前层的走法数等于上一层的走法数+上上一层的走法数,因为最后一步可以一次迈1层,也可以一次迈2层。仅需记录上一层的走法数和上上一层的走法数。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
last = 0
present = 1
for i in range(n):
a = present
present = present + last
last = a
return present
2.动态规划:把每一层的走法数都记录下来,动态转移方程为:res[i] = res[i-1] + res[i-2]
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n<3:
return n
res = [0]*n
res[0] = 1
res[1] = 2
for i in range(2,n):
res[i] = res[i-1] + res[i-2]
return res[n-1]
198.打家劫舍
思路:
1.动态规划:用了2个数组,一个用来记录之前的最大值,一个用来记录当前的结果(最大值)
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
l = len(nums)
if l ==1:
return nums[0]
max_list = [0] * l
res = [0] * l
res[0] = nums[0]
res[1] = nums[1]
max_list[1] = nums[0]
for i in range(2,l):
max_list[i] = max(max_list[i-1],res[i-1])
res[i] = max_list[i-1] + nums[i]
return max(res[l-2],res[l-1])
2.仅用1个数组
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
l = len(nums)
if l ==1:
return nums[0]
res = [0] * l
res[0] = nums[0]
res[1] = max(nums[0],nums[1])
for i in range(2,l):
res[i] = max(res[i-1],res[i-2] + nums[i])
return res[l-1]
3.常量空间(由于只用到了前一个值和前一个值之前的最大值,所以不用记录数组,只记录2个变量也行。)
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
l = len(nums)
if l ==1:
return nums[0]
before_pre = nums[0]
pre = max(before_pre, nums[1])
for i in range(2,l):
ans = max(pre, before_pre + nums[i])
before_pre = pre
pre = ans
return pre
120.三角形最小路径和
思路:
1.动态规划:用1个和输入数组一样大的数组记录上一层的最短路径长度,当前层所有值的最短路径长度就等于最小的邻接上层长度加上当前值。
即状态转移方程为:ans[i][j] = min(ans[i-1][j-1],ans[i-1][j]) + triangle[i][j]
对于每一行的第0个值和最后一个值特殊处理一下。(只有一种选择)
class Solution(object):
def minimumTotal(self, triangle):
"""
:type triangle: List[List[int]]
:rtype: int
"""
l = len(triangle)
ans = triangle
for i in range(1,l):
w = len(triangle[i])
for j in range(w):
if j == 0: #每一行的第0个结点特殊处理
ans[i][j] = ans[i-1][j] + triangle[i][j]
elif j == w-1: #每一行的最后1个结点特殊处理
ans[i][j] = ans[i-1][j-1] + triangle[i][j]
else: #其余的常规情况统一处理
ans[i][j] = min(ans[i-1][j-1],ans[i-1][j]) + triangle[i][j]
return min(ans[l-1])
2.动态规划O(n)空间复杂度:因为每次只会用到上一层的值,所以不用保存所有层的值,仅保存上一层的值即可,所以可以只用O(n)空间复杂度。
#用了两个数组来存储,O(2n) = O(n)
class Solution(object):
def minimumTotal(self, triangle):
"""
:type triangle: List[List[int]]
:rtype: int
"""
l = len(triangle)
m = len(triangle[l-1])
ans = [0]*m
tmp = [0]*m
ans[0] = triangle[0][0]
for i in range(1,l):
w = len(triangle[i])
tmp[0] = ans[0] + triangle[i][0]
tmp[w-1] = ans[w-2] + triangle[i][w-1]
for j in range(1,w-1):
tmp[j] = min(ans[j-1],ans[j]) + triangle[i][j]
ans = tmp[:]
return min(ans)
仅用一个数组存储也可,仅需把for j in range(1,w-1)这里的遍历改为逆序即可。for j in range(w-1,1,-1),这样不会把前面的值要用的覆盖掉。
(从前往后遍历会覆盖掉,因为下一行总是比上一行多一个值,而从后往前遍历的时候,覆盖掉的值往后移了一位,就不会影响到前面要用的值了。)
本道题也可以自下向上的动态规划,这样最后的dp[0]就是要返回的值。