13.算法进阶之路径规划(斐波那契数列求解、钢条切割问题和最长公共序列)

1.斐波那契数列(每一个数,等于前两个数之和)

思想:1)递归思想,把每一个数化成前两个数的和,然后依次迭代,但效率极低

           2)从前往后,把数列每一项存起来,然后依次取用即可。

# 开发时间: 22:59

#问题:递归子问题重复计算,造成效率低
def fibnacci(n):
    if n==1 or n==2:
        return 1
    else:
        return fibnacci(n-1)+fibnacci(n-2)
print(fibnacci(20))

#f(5)=f(4)+f(3)
#f(4)=f(3)+f(2)
#f(3)=f(2)+f(1),求f(5)的f(3)
#f(3)=f(2)+f(1),求f(4)的f(3)
#由上述可知,会出现f(3)重复计算,当n大一些时,计算会比较慢


#动态规划(DP)的思想 = 递推式 + 重复子问题,
def fibnacci_no_rec(n):
    f=[0,1,1]
    if n<=2:
        return f[n]
    else:
        for i in range(n-2):
            num=f[-1]+f[-2]
            f.append(num)
        return f[n]
print(fibnacci_no_rec(20))

2..钢条切割问题(有一根钢条,怎么切割出售,可以使获得的利益最大化。)

思想:1)把最长一刀切成两段,共有n-1中切法,如果每一段最优解已知(每一段的最优解可以通过迭代来计算,直到不可再切割),则就可以求出这第一刀切完之后可以获得的最大利润,找出这n-1种切法的最大值即为最大利益。

           2)从小到大,把每个长度可求的最优解存起来,然后只需求最后一刀时调用即可,没有重复计算问题

# 开发时间: 10:09
from cal_time import cal_time
p20=[0,1,5,8,9,10,17,17,20,21,23,24,26,27,27,28,30,33,36,39,40]
p=[0,1,5,8,9,10,17,17,20,24,30]             #p中存储的每种对应下标长度的价格

#递归问题求计算时间
@cal_time
def cut_rod_1(p,n):
  return  cut_rod_rec_1(p,n)

#递归求解,时间复杂度2^n,自上而下求解,最长的最优解分解为求两端的最优解,依次迭代
def cut_rod_rec_1(p,n):
    if n==0:
        return 0
    else:
        res=p[n]
        for i in range(1,n//2):
            res=max(res,cut_rod_rec_1(p,i)+cut_rod_rec_1(p,n-i))
        return res
#递归问题求计算时间
@cal_time
def cut_rod_2(p,n):
    return cut_rod_rec_2(p,n)

#非递归问题第二种,时间复杂度2^n,自上而下求解,最长的最优解分解为求两端的最优解,依次迭代
def cut_rod_rec_2(p,n):
    if n==0:
        return 0
    else:
        res=p[n]
        for i in range(1,n+1):
            res=max(res,p[i]+cut_rod_rec_2(p,n-i))
        return res


#非递归求解,时间复杂度n^2,自下而上求解。把最小的切割方案存起来,长的分解为的短的直接调用即可
def cut_rod_no_rec(p,n):
    res=[0]
    for i in range(1,n+1):
        res=0
        for j in range(1,i+1):
            temp=max(res,p[j]+res[i-j])
        res.append(res)
    return res[n]
#非递归求解,输出最优价格和切割钢条的方案
def cut_rod_solution(p,n):
    res = [0]
    s=[0]
    ans = []
    for i in range(1, n + 1):
        res_r=0  #存储最优价格
        res_s=0  #记录存储价格所对应的左端未切割的长度
        for j in range(1, i + 1):
            if p[j] + res[i - j] > res_r:
                res_r=p[j] + res[i - j]
                res_s=j
        res.append(res_r)
        s.append(res_s)
        k=n
    while n>0:
        ans.append(s[n])
        n-=s[n]
    return res[k],ans




print(cut_rod_1(p,10))
print(cut_rod_2(p,10))
print(cut_rod_solution(p20,20))

3.最长公共序列问题(求两个字符串或者两个列表中的最长公共序列)

思想:从短往长计算,先比较最后一项,如果相等,则最长公共序列加上相等的这一项,并存起来,否则最长公共序列即为{第一个字符串去掉最后一项和第二个字符串的最长公共序列}与{第一个字符串和去掉最后一项第二个字符串的最长公共序列}中的最大值。

# 开发时间: 14:58
def lcs_length(x,y):
    m=len(x)
    n=len(y)
    c=[[0for _ in range(n+1)]for _ in range(m+1)]
    b=[[0for _ in range(n+1)]for _ in range(m+1)]
    for i in range(1,m+1):
        for j in range(1,n+1):
            if x[i-1]==y[j-1]:
                c[i][j]=c[i-1][j-1]+1
                b[i][j]=1          #箭头指向左上方,数据从上左上方来
            elif c[i-1][j]>=c[i][j-1]:
                c[i][j]=c[i-1][j]
                b[i][j]=2          #箭头指向上,数据从上方来
            else:
                c[i][j]=c[i][j-1]
                b[i][j]=3          #箭头指向左,数据从上左方来
    return c[m][n],b

def lcs_trackback(x,y):
    c,b=lcs_length(x,y)
    i=len(x)
    j=len(y)
    res=[]
    while i>0 and j>0:
        if b[i][j]==1:          #箭头指向左上方,数据从上左上方来,最后一个相等,所以添加进去
            res.append(x[i-1])
            i-=1
            j-=1
        elif b[i][j]==2:        #箭头指向上,数据从上方来
            i-=1
        else:                   #箭头指向左,数据从上左方来
            j-=1

    return ''.join(reversed(res))


a=lcs_trackback('ABCBDABABCD','BDCABABCDA')
print(a)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值