Leetcode 学习计划之21天算法 (十二)

第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]就是要返回的值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值