动态规划入门---最长公共子序列


前言:本来是给我朋友小达人写的,比写作文还认真,这里分享给大家,有不足的地方请多多指教。

动态规划(DP,Dynamic Programming)

​ 我认为动态规划是所有算法中最最重要的,也是最最难的。在我看来它也是真正意义上省时间一种算法,除此之外的其它算法我姑且称之为暴力算法。它主要是用空间来换取时间,这是很值的,因为它将指数级别的时间复杂度直接降为多项式级别。这个寒假搞懂太值了。

定义

​ 动态规划的核心思想就是把原问题分解成若干个子问题进行求解,其利用的就是分治法的思想。但与分治法不同的是,分治法是把原问题分解成若干个子问题,分别解决各个子问题来组合成原问题的解,子问题之间没有相互的关系,是相互独立的。而动态规划中的子问题之间是有联系的,有重叠子问题,根据子问题的解来一步一步地递推出原问题的解,注意是递推而不是分治法的简单的组合。

动态规划问题的特点

​ 先来看个栗子吧。

最长公共子序列问题(LCS)。

​ 子序列是指一串序列中选出几个元素按顺序组成的序列,如because,其中eau、bs、case就是它的一部分子序列,共有2^7-1个,因为为空不算。那么两串序列的最长公共子序列就很好理解了,比如序列A为abcdefghijk和序列B为aahcdekfg,则A和B的最长公共子序列就是acdefg。先假设一般A串为a1,a2,a2,a4…ai,共i个元素(字母),B串为b1,b2,b3…bj,共j个元素。求A和B的最长公共子序列的长度。

分析

​ 先设一个结构C[i,j],它是一个二维数组,你可以把它看出等一张二位表格。前面说过动态规划是用空间来换时间的,而且动态规划的子问题具有重叠性,这张表就是动态规划中所使用的记录重叠子问题的数据结构。接下来的所有操作都是维护这张表,并从这张表中推断出最优解。C[i,j]中i表是A中下标为1i的字串,j表示B中下表为1j的字串,C[i,j]表示a1,a2,a3…ai和b1,b2,b3…bj的最长公共子序列的长度。

1.当i=0或j=0时,有一个串为空,所以C[i,j]=0。

3.当ai=bj时,那么ai就是最长公共子序列中的元素,而且是最后一个,所以最长公共子序列的长度是C[i-1,j-1]+1。

3.当ai!=bj时,那么最长公共子序列就是C[i-1,j]和C[i,j-1]中的最大一个,所以最长公共子序列就是Max(C[i-1,j],C[i,j-1])。

Nice,递推关系式(别人叫状态转移方程,太高大上了,还听不懂,其实就是高中学的递推和分类讨论)找到了。

​ 0 i=0或j=0

C[i,j] = C[i-1,j-1]+1 ai=bj

​ Max(C[i-1,j],C[i,j-1]) ai!=bj

实现

​ 动态规划的实现方式有两种:自底向上和自顶向下。 这里我们先使用最简单容易理解的自顶向下,也叫做备忘录算法,一般使用递归的形式,所以时间上不如自底向上,这里的备忘录就是刚才的那个二维表C,至于为什么叫备忘录待会儿就显而易见了。

​ 递归肯定先定义一个函数了,我们定义函数为fun(i,j),意义为a1,a2…ai和b1,b2…bj的最长公共子序列的长度,根据我们之前推推导的递推关系式就很容易写出函数体。

//我们先把C那张二维表初始化数据都为-1
public int fun(i,j){
   
    if(i==0||j==0){
          //递归的三要素的出口,i=0或j=0。
        C[i][j]=0;
        return C[i][j];
    }
    else if(C[i][j]!=-1){
    //如果之前C表中有计算过的数据,就直接使用,免去重复计算,也就是重叠子问题,这就叫备忘录。
        return C[i][j];   
    }
    else if(a[i]==b[j]){
     //如果ai=bj。
        C[i][j]=fun(i-1,j-1)+1;
        return C[i][j];
    }
    else{
                    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值