动态规划例题:
注意:在DFS遍历,贪心算法和动态规划里面考虑用哪种
动态规划问题思路都是从下往上延申思考
70.爬楼梯
典型斐波拉契数列问题:
解法1:用数组储存每个位置
class Solution:
def climbStairs(self, n: int) -> int:
F = []
F.append(1)
F.append(2)
for i in range(2,n):
F.append(F[i-1]+F[i-2])
return F[n-1]
注意问题:
1. python不能直接给某一位置赋值,例如 F[0] = 1,只能用append实现
2. F.append一次只能添加一个值, 可以改用F.extend([1,2])
解法2:因为只要最后一个位置的值,只用3个位置来存储
class Solution:
def climbStairs(self, n: int) -> int:
if n<=2:
return n
before_one = 1
before_two = 2
all_way = 0
for i in range(2,n):
print(i)
all_way = before_one +before_two
before_one = before_two
before_two = all_way
return all_way
更少内存,只存储3个变量
120.
解法1,递归超时,用DFS回溯遍历所有路径
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
self.count = []
self.triangle = triangle
self.row = len(triangle)
if self.row ==0:
return 0
if self.row == 1:
return triangle[0][0]
self.dfs(0,0,triangle[0][0])
return min(self.count)
def dfs(self,i,j,s):
if i+1>= self.row:
self.count.append(s)
return
self.dfs(i+1,j,s+self.triangle[i+1][j])
self.dfs(i+1,j+1,s+self.triangle[i+1][j+1])
解法二,用倒推法,从下往上循环遍历
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
self.count = []
self.triangle = triangle
self.row = len(triangle)
self.col = len(triangle[-1])
for i in range(self.row-2,-1,-1):
for j in range(0,len(triangle[i])):
triangle[i][j] = triangle[i][j]+ min(triangle[i+1][j],triangle[i+1][j+1])
return triangle[0][0]
解法3:用一维数组复用自身去存储,最后只要第0位即可
注意:
在python2 里面, xrange 比range占用的内存更小。
但在python 3里面,用range即可,更加优化了。
152,求子数列的最大乘积
解法1:双层循环暴力破解法:
用两个点位,第一个点位 i 从 0到len(nums), 第二个点位 j 从 i 到len(nums)
这样两层遍历,遍历所有的子序列,更新出最大乘积
class Solution:
def maxProduct(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
res = nums[0]
for i in range(0,len(nums)):
curmax = 1
for j in range(i,len(nums)):
curmax *= nums[j]
res = max(res,curmax)
return res
解法2:动态规划
两部曲:1.状态的定义 2.状态转移方程
这里的状态定义的很巧妙。DP[i] 表示包含当前i位置值的情况下的maxproduct
为什么这样定义?因为要求必须是连续的子序列
最后要的实际上是看DP[n-1]一直到DP[0] 这一串数字实际的最大值
问题:
如果此时a[i]为负数?
那么dp[i] = dp[i-1]*a[i] 就不为i位置的最大值了 实际上的最大值是在 i-1位置的负最大 * a[i]
制造一个列表:
解法二:动态规划法:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
dp = [[0 for _ in range(2)] for _ in range(2)]
dp[0][0],dp[0][1],res = nums[0],nums[0],nums[0]
for i in range(1,len(nums)):
x ,y = i%2, (i-1)%2
dp[x][0] = max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
dp[x][1] = min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
res = max(res, dp[x][0])
return res
需要注意的点:
我们只保留了两位,原因是我们计算的时候其实只需要保留前一位的子序列最大/最小乘积从而来计算这一位的子序列最大/最小乘积
在每一次循环中我们都求出最大值res并不断更新
为什么要与nums[i]比较?
Input [0,2]
Output 0
Expected 2
对于这个例子而言,如果前一位是0,那么怎么乘后面都变成0了。为了避免这种情况,引入nums[i]来剔除掉只剩0的情况。