动态规划专题 -最大子序列和、硬币找零、最长递增子序列、叠箱子、造桥

推荐网站:一个dp学习网站https://people.cs.clemson.edu/~bcdean/dp_practice/

最大子序列和

描述

对于一个数组(有正有负),找到连续的A[i]…A[j]使其和最大
可以采用动态规划的算法
以M[j]为到下标j时最大的子序列和,那么:
M[j] = max(M[j-1]+A[j], A[j])
显然从M[j-1]阶段到M[j]阶段,只有这两种情况,比较是继续加更合适,还是新开始一个序列更合适
最终遍历M找到最大的即可
时间复杂度为O(n)

leetcode 53为例,代码如下

代码

 def maxSubArray(self, nums: List[int]) -> int:
        if len(nums)==1:
            return nums[0]
        maxsum = [0]*len(nums)
        maxsum[0] = nums[0]
        for i in range(1,len(nums)):
            if maxsum[i-1]+nums[i] >= nums[i]:
                maxsum[i]= maxsum[i-1]+nums[i]
            else:
                maxsum[i] = nums[i]
        result = -1
        for n in maxsum:
            if n > result:
                result = n
        return result

硬币找零

描述

给定一组硬币面值 v1…vn,和一个值C,一般若v1=1可以保证一定能成功找零,求得是找零需要的最少的钱币数
令 M[j]为兑齐钱币j所需的最少的硬币数,那么:
M[j] = min{M[j-vi]}+1
也就是当前状态还没有找齐j,再加一枚面值为vi的硬币可以凑齐,所以就是在现在的找齐(j-vi)面值的情况下再加一枚硬币,就可以找齐面值j

时间复杂度为O(n*C)
LeetCode 322,代码如下:

代码

 def coinChange(self, coins: List[int], amount: int) -> int:
        M = [amount+2]*(amount+2) #找齐j需要的最小硬币数
        M[0] = 0
        for i in range(1,amount+1):
            for j in range(len(coins)):
                if i>=coins[j] and M[i-coins[j]]!= amount+2 : # 注意条件
                    if M[i-coins[j]]+1 < M[i]:
                        M[i] = M[i-coins[j]]+1
        if M[amount] == amount+2: # 无法找齐
            return -1
        else:
            return M[amount]

Longest increasing subsequence

描述

在序列A[1…n]中,找出最长的递增子序列的长度,注意这个不一定是连续的
让L[j]为到下标j为止最长的递增子序列的长度,则
L[j] = max{L[i]}+1 其中 i<j 且 L[i]<L[j]
最后还是遍历一遍找最大的L[j]
时间复杂度为O(n^2),当然,这个也有O(nlogn)的解法

LeetCode 300

代码

def lengthOfLIS(self, nums: List[int]) -> int:
        if len(nums)==0:
            return 0
        elif len(nums)==1:
            return 1
        L = [1]*len(nums)  #初始化为1 因为当前位置至少自己可以构成一个序列

        for j in range(1,len(nums)):
            for i in range(j):
                if nums[i]<nums[j]:
                    if L[i]+1 > L[j]:
                        L[j] = L[i]+1
                
        res = -1
        for n in L:
            if n > res:
                res = n
        return res
            

boxStacking 叠放箱子

描述

这个题和longest increasing subsequence非常像
给定一组箱子的长宽高,分别是di,wi和hi,且di<wi,这样就避免了旋转箱子的问题
在叠箱子的时候,只有当wi<wj 且di<dj时才能把i叠放到j上
在这里插入图片描述
所以让H(j)为顶层为第j个箱子时的最高的高度,那么
H(j) = max{H(i)}+1 条件是 wi<wj 且di<dj
时间复杂度仍然是O(n^2)

build bridge

描述

在这里插入图片描述
如图,河两岸分别是n个城市,要在对应的城市间造桥,但是桥不能交叉,目标是建造最多的桥
这个问题与最长递增子序列非常类似
让x[i]为南岸城市对应的北岸城市的序号,比如x[1]=3, 可以用O(nlogn)时间内填充所有x[i],然后就可以找x[1]…x[n]的最长递增子序列了 (对岸是递增的就不会交叉)
未完待续

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值