动态规划(一)

      本博客所有问题都可能有多种解法,但这里主要讲解其动态规划的算法

1、最长公共子序列

2、最长公共子串

3、最长递增子序列

 

最长公共子序列(LCS)


【问题描述】

      最长公共子序列,英文缩写为LCS,其定义是,一个序列 S ,如果分别是序列(S1,S2……)的子序列,且是所有符合此条件

序列中最长的,则 S称为已知序列的最长公共子序列。需要注意的是序列S并不一定是序列(S1,S2……)中的连续序列。

【DP算法】

      对字符串X=<x1, x2, ……,xm>,Y=<y1,y2,……,yn>,LCS(X,Y)表示X和Y的一个最长公共子序列,观察可得到如下

规则:

1、如果xm=yn,则LCS ( X,Y ) = 1+LCS ( Xm-1,Yn-1 )。

2、如果xm!=yn,则LCS( X,Y )=max{ LCS ( Xm-1, Y ), LCS ( X, Yn-1 ) }

       

【代码】

int LCS(string s1, string s2) {
     intnLen1 = s1.length();
     intnLen2 = s2.length();
     vector<vector<int>>c;
     c.resize(nLen1+ 1); 
     for(inti = 0; i <= nLen1; i++) 
          c[i].resize(nLen2+ 1, 0);
 
     for(int i = 1; i <= nLen1; i++) {
         for(int j = 1; j < nLen2; j++) {
             if(s1[i - 1] == s2[j - 1])
                c[i][j]= c[i - 1][j - 1] + 1;
             else{
                if (c[i - 1][j]> c[i][j - 1])
                   c[i][j]= c[i - 1][j] ;
                else
                   c[i][j]= c[i][j - 1] ;
             }
        }
    }
 
    return c[nLen1][nLen2];
}



最长公共子串

 

【问题描述】

      最长公共子串与最长公共子序列唯一的不同是要求序列S是字符串S1,S2等的连续序列

【DP算法】

      其DP思想与LCS十分相似,只需在状态转移方程上稍作修改

      

【代码】

int LC_continue_S(string s1, string s2) {
     intnLen1 = s1.length();
     intnLen2 = s2.length();
     vector<vector<int>>c;
     c.resize(nLen1+ 1); 
     for(inti = 0; i <= nLen1; i++) 
          c[i].resize(nLen2+ 1, 0);
 
      int nMax= 0;
      for(int i = 1; i <= nLen1; i++) {
           for(int j = 1; j < nLen2; j++) {
                if(s1[i - 1] == s2[j - 1]) {
                    c[i][j]= c[i - 1][j - 1] + 1;
                    if(c[i][j] > nMax)
                        nMax= c[i][j];
                }
                else
                    c[i][j]= 0;
           }
      }
 
     return nMax;
}




最长递增子序列(LIS)

【问题描述】

给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)

【DP算法】

解法1:转化为最长公共子序列问题

将数组arr[]从小到大排序得到sorted_arr[],然后找出最长公共子序列,显然得到的结果亦是最长递增子序列,这里我们不再讲解

解法2:

像LCS一样,从后向前分析,很容易想到,第i个元素之前的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1

个元素之前的最长递增子序列加1,可以有状态方程:

LIS[i] = max{1,LIS[k]+1},其中,对于任意的k<=i-1,arr[i] >arr[k]

这样arr[i]才能在arr[k]的基础上构成一个新的递增子序列。

解法3:二分查找,这里不提供说明,请跳转大神博客点击打开链接

【代码】

解法2代码

int LIS(int arr[],int size) {
    int lis = 0;
    for(int i = 0; i < size; ++i) {
        dp[i] = 1;
        for(int j = 0; j < i; ++j) {
            if(arr[i] > arr[j] && dp[i] < dp[j] + 1) {
                dp[i] = dp[j] + 1;
                if(dp[i] > lis)
                    lis = dp[i];
            }
        }
     }
    return lis;
}





          

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值