dp基础之序列型最长上升子序列

问题 :给定a[i](i=0...n-1),找到最长上升子序列(假设长度为k),输出k

例:
a = [4,2,4,5,3,7]
返回 
k=4([2,4,5,7])
 

分析:
对于最优策略:一定有最后一个元素a[j]
情况1:最优策略就是{a[j]},长度k就是1
情况2:最优策略子序列长度大于1,则最优策略中最后一个元素a[j]前一定有一个元素a[i],且a[i]<a[j](i<j)
       且以a[i]结尾的序列列也是最优的

子问题:f[i]表示以a[i]结尾的最长子序列长度
    f[j] = max{1,f[i]+1 | i<j && a[i]<a[j] } 
 
计算顺序:
f[0]...f[n-1]

时间复杂度O(n^2) ,可以优化至O(N*logN),空间复杂度O(n)

 

代码及注释如下:

def long_sequence(a):
    #f[i]表示以a[i]结尾的上升子序列的长度
    n = len(a)
    if n == 0:
        return ;
    f = [0 for j in range(n)]
    #初始,以a[0]结尾的最长上升子序列长度就是1
    for j in range(n):
        #情况1,f[0] = 1
        f[j] = 1
        #枚举j之前最优子序列长度
        for i in range(j):
            if a[i] < a[j] and f[j] < f[i]+1:
                f[j] = f[i] + 1
    return max(f)
a = [4,2,4,5,3,7]
print(long_sequence(a))
#结果:4

信封问题跟这个类似,就放一起比较

 

问题:给定N个信封的长和宽,如果另一个信封的长和宽更小,则可以被套进信封去,问,最多嵌套多少个信封?

 

分析:
确定状态:
先考虑长度,将所有信封长度从小到大排序
设:最优策略里最外层信封的长度是Ej,则
    次外层信封的长度Ei,也是最优策略,且Ei<Ej(i<j)

子问题:要知道以Ej结尾的最优策略的长度,则我们需要知道以Ei结尾的最优策略

设f[i]是以Ei为最外层信封的最优策略的信封数
    f[i] = max{f[i], f[j] + 1 | Ej在Ei里,j<i}

无初始条件

依次求f[0],...,f[n-1]
需要对信封长度排序,时间复杂度O(N^2),空间复杂度O(N)

 

代码及注释如下:

def doll_envelope(E):
    n = len(E)
    if n == 0:
        return 0
    #f[i]是以Ei为最外层信封的最优策略的信封数
    f = [0 for i in range(n)]
    for i in range(n):
        #f[0] = 1
        f[i] = 1
        for j in range(i):
            #前面的长度小且宽度小,信封j可以放到信封i里
            if E[j][0] < E[i][0] and E[j][1] < E[i][1]:
                f[i] = max(f[i],f[j] + 1)
    return max(f)
A = [[5,4],[6,4],[6,7],[2,3]]
E = sorted(A)
print(doll_envelope(E))
#结果:3

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值