最长公共子序列

求最长公共子序列是校招笔试中常见的题目,比如,有字符串“abcdefg”和“adgkmz”,他们的最长公共子序列是“adg”。实现该算法到了动态规划思想,根据两个序列的长度构造一二维数组,
1.假设两个字符串长度分别为m和n;
·创建1个二维数组L[m+1][n+1];

·初始化L数组内容为0
·m和n分别从1开始,m++,n++循环:
   - 如果str1[m] == str2[n],则L[m,n] = L[m - 1, n -1] + 1;
   - 如果str1[m] != str2[n],则L[m,n] = max{L[m,n - 1],L[m - 1, n]}
·最后从L[m,n]中的数字一定是最大的,且这个数字就是最长公共子序列的长度
2.从数组L中查找一个最长的公共子序列

i和j分别从m,n开始,递减循环直到i = 0,j = 0。其中,m和n分别为两个串的长度。
·如果str1[i] == str2[j],则将str[i]字符插入到子序列内,i–,j–;
·如果str1[i] != str[j],则比较L[i,j-1]与L[i-1,j],L[i,j-1]大,则j–,否则i–;(如果相等,则任选一 个)

最长公共子序列_第1张图片

实现代码如下:

<!-- lang: cpp -->
#include<stdio.h>
#include<string.h>
void FindMaxSub(char A[], char B[])
{
    char buffer[50];
    int m=strlen(A),n=strlen(B);
    int arr[m+1][n+1];
    int i,j,top=-1;
    for(i=0;i<=m;i++)
    {
        for(j=0;j<=n;j++)
            arr[i][j]=0;
    }
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=n;j++)
        {
            if(A[i-1]==B[j-1]) arr[i][j]=arr[i-1][j-1]+1;
            else //arr[i][j]=(arr[i-1][j]>arr[i][j-1]?arr[i-1][j]:arr[i][j-1]);
            {
                if(arr[i-1][j]>arr[i][j-1]) arr[i][j]=arr[i-1][j];
                else arr[i][j]=arr[i][j-1];
            }       
        }
    }
    for(i=0;i<=m;i++)
    {
        for(j=0;j<=n;j++)
        {
            printf("%d ",arr[i][j]);
        }
        printf("\n");
    }
    for(i=m,j=n;i>0&&j>0;)
    {
        if(A[i-1]==B[j-1])
        {
            top++;
            buffer[top]=A[i-1];
            i--;
            j--;
        }
        else
        {
            if(arr[i][j-1]>arr[i-1][j]) j--;
            else i--;
        }
    }

    for(i=top;i>=0;i--)
    {
        printf("%c ",buffer[i]);
    }
}

void main()
{
    char a[]="abcdefg";
    char b[]="adgkmzfhig";
    FindMaxSub(a,b);
    printf("\n");
}

运行结果(linux下运行结果):
最长公共子序列_第2张图片

———-未完待续————–
目前只是输出子序列中的一种,有可能两个字符串的最大公共子序列不止一种,后续继续研究,争取尽快实现。

你可能感兴趣的:(最长公共子序列)