最长公共子序列——有重复解时的全解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zpalyq110/article/details/79994001

解题思路:
求两个字符串的最长公共子序列,这是一道经典的动态规划的问题,大致需要两个过程:
假设两个字符串的长度分别为m、n;

  • 建立表格:c[][]数组记录字符相等数,遍历m*n次,判断字符是否一样,相等max(left,top)+1,不相等取max(left,top);同时填充d[][]数组,记录的是路径的方向,以便后面回溯出最长公共子序列,0、1、2、3分别代表lefttop、top、left、left==top。

这里写图片描述

  • 回溯公共子串:比较麻烦的情况就是多个解,需要定义一个全局变量来存放所有解,并且在分支前记录两个解的公共前缀。

代码:

#include <iostream>
#include<string>
#include<vector>
#include<set>
using namespace std;

set<string> setOfLCS;

int LCSlen(string str1, string str2, int **d) {
    int len1 = str1.size();
    int len2 = str2.size();

    int **c = new int*[len1 + 1];//行数
    for (int i = 0; i < len1 + 1; i++) {
        c[i] = new int[len2 + 1];//列数
    }
    for (int i = 0; i < len1 + 1; i++)
        c[i][0] = 0;
    for (int i = 0; i < len2 + 1; i++)
        c[0][i] = 0;
    for (int i = 1; i < len1 + 1; i++)
    {
        for (int j = 1; j < len2 + 1; j++)
        {
            if (str1[i - 1] == str2[j - 1])//c的第i行元素对应str1的第i-1个元素  
            {
                c[i][j] = c[i - 1][j - 1] + 1;
                d[i][j] = 0;          //方向 : lefttop
            }
            else if (c[i - 1][j] > c[i][j - 1])
            {
                c[i][j] = c[i - 1][j];
                d[i][j] = 1;         //方向 : top
            }
            else if (c[i - 1][j] < c[i][j - 1])
            {
                c[i][j] = c[i][j - 1];
                d[i][j] = 2;       //方向 : left
            }
            else
            {
                c[i][j] = c[i][j - 1];
                d[i][j] = 3;       //方向 :top==left
            }
        }
    }
    return c[len1][len2];
}


void PrintLCS(int **d, string str1, string lcs, int i, int j)
{
    while (i >0 && j >0){
        if (d[i][j] == 0)
        {
            string ss;
            ss = str1[i - 1];
            lcs.insert(0, ss);
            i--;
            j--;
        }
        else if (d[i][j] == 1)
              i -- ;// top
        else if(d[i][j] == 2)
             j --; // left
        else
        {
            PrintLCS(d, str1, lcs, i - 1, j);
            PrintLCS(d, str1, lcs, i , j - 1);
            return;
        }
    }
    setOfLCS.insert(lcs);
}



int main() {
    string str1, str2;
    cout << "请输入第一个字符串:" << endl;
    cin >> str1;
    cout << "请输入第二个字符串:" << endl;
    cin >> str2;
    //str1 = "ABCBDAB";
    //str2 = "BDCABA";
    int len1 = str1.size();
    int len2 = str2.size();
    int **d = new int*[len1 + 1];//行数
    for (int i = 0; i < len1 + 1; i++) {
        d[i] = new int[len2 + 1];//列数
    }
    int len = LCSlen(str1, str2, d);
    cout << "最长公共子序列的长度为:" << len << endl;
    cout << "最长公共子序列为:"  << endl;
    string lcs;
    PrintLCS(d, str1, lcs,len1, len2);
    set<string>::iterator beg = setOfLCS.begin();
    for (; beg != setOfLCS.end(); ++beg)
        cout << *beg << endl;
    system("pause");
    return 0;
 }

猜你喜欢

转载自blog.csdn.net/zpalyq110/article/details/79994001