最长公共子序列问题模板(不要求连续)

首先我贴个简单的模板,用dfs来解决的

int LCS(int i,int j)
{
    if(i>=lena || j>=lenb)
        return 0;
    if(a[i]==b[j])
        return 1+LCS(i+1,j+1);
    else
        return LCS(i+1,j)>LCS(i,j+1)? LCS(i+1,j):LCS(i,j+1);
} //用的时候是LCS(0,0)

有时候我们需要把公共子序列求出

void LCS()
{
    int i,j;
    for(i=1;i<=strlen(a);i++)
    {
        for(j=1;j<=strlen(b);j++)
        {
            if(a[i-1]==b[j-1])   ///注意这里的下标是i-1与j-1
            {
                num[i][j]=num[i-1][j-1]+1;
                flag[i][j]=1;  ///斜向下标记
            }
            else if(num[i][j-1]>num[i-1][j])
            {
                num[i][j]=num[i][j-1];
                flag[i][j]=2;  ///向右标记
            }
            else
            {
                num[i][j]=num[i-1][j];
                flag[i][j]=3;  ///向下标记
            }
        }
    }
}

void getLCS()
{

    char res[500];
    int i=strlen(a);
    int j=strlen(b);
    int k=0;    ///用于保存结果的数组标志位
    while(i>0 && j>0)
    {
        if(flag[i][j]==1)   ///如果是斜向下标记
        {
            res[k]=a[i-1];
            k++;
            i--;
            j--;
        }
        else if(flag[i][j]==2)  ///如果是斜向右标记
            j--;
        else if(flag[i][j]==3)  ///如果是斜向下标记
            i--;
    }

    for(i=k-1;i>=0;i--)
        printf("%c",res[i]);
}

下面是最长公共子序列nlogn算法,有可能退化,转自bin314 的BLOG

最长公共子序列问题:
给定2个字符串,求其最长公共子串。如abcde和dbada的最长公共字串为bd。
动态规划:dp[i][j]表示A串前i个和B串前j个的最长公共子串的长度。

若A[i] == B[j] , dp[i][j] = dp[i-1][j-1] + 1;
否则 dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
时间复杂度O(N*M)。
dp[i][j]仅在A[i]==B[j]处才增加,对于不相等的地方对最终值是没有影响的。
故枚举相等点处可以对其进行优化。
则对于dp[i][j](这里只计算A[i]==B[j]的i和j),取最大的dp[p][q],满足(p

#include <stdio.h>  
#include <ctype.h>  
#include <string.h>  
#include <iostream>  
#include <string>  
#include <math.h>  
#include <vector>  
#include <queue>  
#include <algorithm>  

using namespace std;  

const int maxn = 1501 ;  
vector<int> location[26] ;  
int c[maxn*maxn] , d[maxn*maxn] ;  

inline int get_max(int a,int b) {   return a > b ? a : b ;  }  

//nlogn 求lcs  
int lcs(char a[],char b[])  
{  
    int i , j , k , w , ans , l , r , mid ;  
    for( i = 0 ; i < 26 ; i++) location[i].clear() ;  
    for( i = strlen(b)-1 ; i >= 0 ; i--) location[b[i]-'a'].push_back(i) ;  
    for( i = k = 0 ; a[i] ; i++)  
    {  
        for( j = 0 ; j < location[w=a[i]-'a'].size() ; j++,k++) c[k] = location[w][j] ;  
    }  
    d[1] = c[0] ;   d[0] = -1 ;  
    for( i = ans = 1 ; i < k ; i++)  
    {  
        l = 0 ; r = ans ;  
        while( l <= r )  
        {  
            mid = ( l + r ) >> 1 ;  
            if( d[mid] >= c[i] ) r = mid - 1 ;  
            else l = mid + 1 ;  
        }  
        if( r == ans ) ans++,d[r+1] = c[i] ;  
        else if( d[r+1] > c[i] ) d[r+1] = c[i] ;  
    }  
    return ans ;  
}  

int main()  
{  
    char a[maxn] , b[maxn] ;  
    while (~scanf("%s%s",a,b))  
    {  
        printf("%d\n",lcs(a,b));  
    }  
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值