求两个字符串的最长公共子序列 合工大 程序设计艺术实验四

求两个字符串的最长公共子序列.
X的一个子序列是相应于X下标序列{1, 2, …, m}的一个子序列,求解两个序列的所有子序列中长度最大的,例如输入:pear,peach输出pea.

首先你要明白什么是最长公共子序列,例如 asd5gd 和 s5666d 的最长公共子序列为s5d

在两个字符串中,有些字符会一样,可以形成的子序列也有可能相等,因此,长度最长的相等子序列便是两者间的最长公共字序列,其长度可以使用动态规划来求。

以s1={1,3,4,5,6,7,7,8},s2={3,5,7,4,8,6,7,8,2}为例。

借用《算法导论》中的推导图:

创建 DP数组C[][];

在这里插入图片描述

图中的空白格子需要填上相应的数字(这个数字就是c[i][j]的定义,记录的LCS的长度值)。填的规则依据递归公式,简单来说:如果横竖(i,j)对应的两个元素相等,该格子的值 = c[i-1,j-1] + 1。如果不等,取c[i-1,j] 和 c[i,j-1]的最大值。首先初始化该表:

在这里插入图片描述

      然后,一行一行地从上往下填:

在这里插入图片描述

      S1的元素3 与 S2的元素3 相等,所以 c[2,1] = c[1,0] + 1。继续填充:

在这里插入图片描述

        S1的元素3 与 S2的元素5 不等,c[2,2] =max(c[1,2],c[2,1]),图中c[1,2] 和 c[2,1] 背景色为浅黄色。

        继续填充:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

           中间几行填写规则不变,直接跳到最后一行:

在这里插入图片描述
至此,该表填完。根据性质,c[8,9] = S1 和 S2 的 LCS的长度,即为5。

为了打印路径,所以在代码里增添了一个新的数组用来记录路径.
在这里插入图片描述


#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAXLEN 100

using namespace std;

void LCSLength(char *x, char *y, int m, int n, int c[][MAXLEN], int b[][MAXLEN])
{
    
    
    int i, j;

    for(i = 0; i <= m; i++)
        c[i][0] = 0;
    for(j = 1; j <= n; j++)
        c[0][j] = 0;                
    for(i = 1; i<= m; i++)
    {
    
    
        for(j = 1; j <= n; j++)
        {
    
    
            if(x[i-1] == y[j-1])
            {
    
    
                c[i][j] = c[i-1][j-1] + 1;
                b[i][j] = 0;
            }
            else if(c[i-1][j] >= c[i][j-1])
            {
    
    
                c[i][j] = c[i-1][j];
                b[i][j] = 1;
            }
            else
            {
    
    
                c[i][j] = c[i][j-1];
                b[i][j] = -1;
            }
        }
    }
}

void PrintLCS(int b[][MAXLEN], char *x, int i, int j)
{
    
    
    if(i == 0 || j == 0)
        return;
    if(b[i][j] == 0)
    {
    
    
        PrintLCS(b, x, i-1, j-1);
        printf("%c ", x[i-1]);
    }
    else if(b[i][j] == 1)
        PrintLCS(b, x, i-1, j);
    else
        PrintLCS(b, x, i, j-1);
}

int main(int argc, char **argv)
{
    
    
    char x[MAXLEN];
    char y[MAXLEN];
    int b[MAXLEN][MAXLEN];
    int c[MAXLEN][MAXLEN];
    int m, n;

    cout << "请输入两个字符串:" << endl;

    scanf("%s", x);
    scanf("%s", y);

    m = strlen(x);
    n = strlen(y);

    LCSLength(x, y, m, n, c, b);

    cout  << "两个字符串的最大公共子序列是:" ;

    PrintLCS(b, x, m, n);

    return 0;
}

参考博客:https://blog.csdn.net/someone_and_anyone/article/details/81044153?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159110780919725247601128%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159110780919725247601128&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-4-81044153.first_rank_ecpm_v3_pc_rank_v3&utm_term=%E6%9C%80%E9%95%BF%E5%85%AC%E5%85%B1%E5%AD%90%E5%BA%8F%E5%88%97

Guess you like

Origin blog.csdn.net/qq_42650433/article/details/106505282