您的位置:首页 > 其它

LCS, LIS, 线性空间LCS( hirschberg算法)

2009-11-22 22:20 471 查看
今天帮同学写了三个代码,分别是简单LCS,LIS,以及使用线性空间的LCS。

首先是LCS(longest common substring最长公共子序列),这是动态规划的典型例题,各种算法书里都会讲到的一个问题。个人推荐这个网页http://blog.163.com/hzzy-010/blog/static/79692381200872024242126/ 。 讲的非常清楚,图例也很好,可以把你从不懂讲到懂。由于他讲的实在很详细,我就不好意思再说了。直接上代码了。代码比较搓,将就着看吧。

#include<stdio.h>
#include<string.h>

#define MAXLEN 100

int max_three(int a,int b,int c,int &back)
{
    int max = a;
    back = 0;
    if(max < b)
    {
        max = b;
        back = 1;
    }
    if(max < c)
    {
        max = c;
        back = 2;
    }
    return max;
}

int main()
{
    char x[MAXLEN];
    char y[MAXLEN];
    int matrix[MAXLEN][MAXLEN];
    int back[MAXLEN][MAXLEN];

    char result[MAXLEN];
    printf("input string a/n");
    scanf("%s",&x);
    printf("input string b/n");
    scanf("%s",&y);

    int xlen = strlen(x);
    int ylen = strlen(y);

    for(int i=0;i<xlen;i++)
    {
        for(int j=0;j<ylen;j++)
        {
            matrix[i][j] = 0;
        }
    }

    for(int i=1;i<=xlen;i++)
        for(int j=1;j<=ylen;j++)
        {
            if(i*j!=0)
            {
                if(x[i-1] == y[j-1])
                {
                    matrix[i][j] = max_three(matrix[i-1][j-1]+1, matrix[i][j-1],matrix[i-1][j], back[i][j]);
                }else
                {
                    matrix[i][j] = max_three(matrix[i-1][j-1], matrix[i][j-1],matrix[i-1][j], back[i][j]);
                }
            }
        }
    printf("the LCS length is %d/n",matrix[xlen][ylen]);
    
    int xx = xlen;
    int yy = ylen;

    char ans[MAXLEN];
    int ansl=0;

    while(true)
    {
        if(back[xx][yy] == 0&& x[xx-1] == y[yy-1])
        {
            ans[ansl++] = x[xx-1];
        }
        if(back[xx][yy] == 0)
        {
            xx--;
            yy--;
        }
        else if(back[xx][yy] == 1)
        {
            yy--;
        }else
            xx--;
        if(xx == 0&&yy == 0)
            break;
    }
    printf("the LCS is:/n");
    for(int i=matrix[xlen][ylen]-1;i>=0;i--)
        printf("%c",ans[i]);
    printf("/n");
}


LIS(longest increasing substring)也是一个动态规划问题,有O(n2)以及O(nlogn)两种解法,我用了比较简单的算法。具体的递推公式是:len(i) = max{str[i] > str[j]? len[i]+1 : 1} 0=< j < i; 然后我们从len的数组中找到最长子串,注意不是说最后一个len一定是最长的。然后输出。代码如下:

#include<stdio.h>
#include<string.h>

#define MAXLEN 100

int main()
{
    char x[MAXLEN];
    int l[MAXLEN];
    int pro[MAXLEN];

    for(i=0;i<MAXLEN;i++)
    {
        l[i] = 1;
        pro[i] = -1;
    }

    printf("input the string:/n");
    scanf("%s",&x);
    l[0] = 1;
    pro[0] = -1;
    int len = strlen(x);
    for(int i=1;i<len;i++)
    {
        int max = 0;
        pro[i] = -1;
        for(int j=0;j<i;j++)
        {
            l[i] = x[i] > x[j]?l[j]+1:1;
            if(max <l[i])
            {
                max = l[i];
                pro[i] = j;
            }
        }
        l[i] = max;
    }
    
    int lis = l[len-1];
    int sub = len-1;

    for(int i=len-2;i>=0;i--)
    {
        if(lis <l[i])
        {
            lis = l[i];
            sub = i;
        }
    }

    printf("the length of LIS is:%d/n",lis);

    char ans[MAXLEN];
    int ansl=0;

    int i = sub;

    while(pro[i]!=-1)
    {
        ans[ansl++] = x[i];
        i = pro[i];
    }
    printf("the LIS is:/n%c",x[i]);
    for(int i=ansl-1;i>=0;i--)
    {
        printf("%c",ans[i]);
    }
    printf("/n");
}


线性空间LCS,这是使用线性的空间来解LCS问题,主要为了解决长字符串而由hirschberg发明的。可以看维基上的介绍:http://en.wikipedia.org/wiki/Hirschberg%27s_algorithm,当然也可以找他的论文看看,名字叫:A Linear Space Algorithm for Computing Maximal Common Subsequences 。这个解法使用到了动态规划以及分治算法,在时间复杂度上面有所增加,但是减少了空间复杂度。它首先把a数组一分为二,然后考虑所有的b数组二分的方法,找到一个subsequence最长的方法,然后将两个数组一分为二,分别再次计算。这个算法之所以可以成功,还有一个原因就是下面代码中的LCS_B算法可以使用线性空间获得最长子序列的长度。好了,代码如下:

#include<stdio.h>
#include<string.h>

#define MAXLEN 100

void reverstring(char* x,char* xr)
{
    int len = strlen(x);
    for(int i=0;i<len;i++)
    {
        xr[i] = x[len-i-1];
    }
    xr[len] = '/0';
}

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

void LCS_B(int m, int n, char* A, char* B, int& L)
{
    int K[2][MAXLEN];
    for(int j=0;j<=n;j++)
        K[1][j] = 0;
    for(int i=1;i<=m;i++)
    {
        for(int j=0;j<=n;j++)
            K[0][j] = K[1][j];
        for(int j=1;j<=n;j++)
        {
            if(A[i-1] == B[j-1])
            {
                K[1][j] = K[0][j-1]+1;
            }
            else
                K[1][j] = max(K[1][j-1],K[0][j]);
        }
    }
    L = K[1]
;
}

void LCS_A(int m,int n,char* x, char* y, char* res)
{
    char xr[MAXLEN];
    char yr[MAXLEN];

    x[m] = '/0';
    y
 = '/0';

    reverstring(x, xr);
    reverstring(y, yr);

    if(n==0)
    {
        strcpy(res,"");
        return;
    }
    if(m==1)
    {
        for(int i=0;i<n;i++)
        {
            if(x[0] == y[i])
            {
                res[0] = x[0];
                res[1] = '/0';
                break;
            }
        }
        return;
    }

    int i = m/2;

    int maxsum = -1;
    int k = -1;

    for(int j=0;j<=n;j++)
    {
        int L1,L2;
        L1 = L2 = 0;
        LCS_B(i,j,x,y,L1);
        LCS_B(m-i,n-j,xr,yr,L2);
        if(maxsum < L1+L2)
        {
            maxsum = L1+L2;
            k = j;
        }
    }

    char c1[MAXLEN];
    char c2[MAXLEN];

    char xx[MAXLEN];
    char yy[MAXLEN];

    int xsub = 0;
    int ysub = 0;

    for(int j=i;j<=m;j++)
    {
        xx[xsub++] = x[j];
    }
    
    for(int j=k;j<=n;j++)
    {
        yy[ysub++] = y[j];
    }

    LCS_A(i,k,x,y,c1);
    LCS_A(m-i,n-k,xx ,yy ,c2);
    strcat(c1,c2);
    strcpy(res,c1);
}

int main()
{
    char x[MAXLEN];
    char y[MAXLEN];
    char res[MAXLEN];

    printf("input string a:/n");
    scanf("%s",&x);
    printf("input string b:/n");
    scanf("%s",&y);
    
    LCS_A(strlen(x),strlen(y),x,y,res);
    printf("the length is: %d/n",strlen(res));
    printf("the LCS is:/n%s/n",res);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: