2021-06-27:动态规划例题,70爬楼梯,120三角路径

本文探讨了动态规划的解题思路,通过70题爬楼梯和120题三角路径为例,讲解了动态规划问题的解决方法。强调了在Python中处理动态规划时的注意事项,并对比了不同解法的优缺点。此外,还介绍了152题求子数列最大乘积的动态规划解决方案,特别讨论了负数情况下如何处理状态转移。
摘要由CSDN通过智能技术生成

 动态规划例题:

注意:在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的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值