Algorithm3——最长公共子序列(LCS)

本系列算法实现都是在学习数据结构(C++语言版),清华大学邓俊辉教授编,听邓老师edX网课过程中自己实现的例子。

参考链接

问题:
(1)找到LCS的长度
(2)找到其中一个LCS序列
(3)找出所有LCS序列

解决: 以下代码实现解决以上三个问题,第一个链接主要解决第三个问题,第二个链接解决第一二两个问题

1 LCS算法接口

我把它封装成了一个类,接口如下

#include <iostream>
#include <string>
#include <eigen3/Eigen/Eigen>
#include <set>

class LongestCommonSubsequence
{
public:
    LongestCommonSubsequence(const std::string& _s1, const std::string& _s2);
    ~LongestCommonSubsequence();
    void get_lcs_one(std::string& str);
    void get_lcs_set(std::set<std::string>& strset);
    int get_lcs_length();
    void print_lcs_set();

private:
    std::string s1, s2; //str
    Eigen::MatrixXi len_mat;//table matrix
    std::set<std::string> lcs_set;//lcs set

    void lcs_creat_table();
    void lcs_back_traversal(int i, int j, std::string str);
};

2 找到LCS的长度

LCS的长度为所建立的矩阵的右下角元素

int LongestCommonSubsequence::get_lcs_length()
{
    return len_mat(s1.length(), s2.length());
}

建立矩阵如下

//! class LongestCommonSubsequence private interface BEGIN
void LongestCommonSubsequence::lcs_creat_table()
{
    for (auto i = 1; i <= s1.length(); i++)
    {
        for (auto j = 1; j <= s2.length(); j++)
        {
            //equal,OBLIQUE_UP_LEFT
            if (s1[i - 1] == s2[j - 1])
                len_mat(i, j) = len_mat(i - 1, j - 1) + 1;
            else
                len_mat(i, j) = std::max(len_mat(i - 1, j), len_mat(i, j - 1));//UP
        }
    }
}

3 找到其中一个LCS序列

这个问题和第三个类似,主要区别在于如果想要找到全部的子序列,需要从矩阵的右下角回溯到左上角,需要用到递归。而只找一个子序列只是其中的一个特殊情况,所有可以直接注释一部分找到全部子序列的代码。

void LongestCommonSubsequence::get_lcs_one(std::string& str)
{

    auto i = s1.length();
    auto j = s2.length();

    while (i && j)
    {
        if (s1[i - 1] == s2[j - 1])
        {
            str = s1[i - 1] + str;
            i--;
            j--;
        }
        else
        {
            if (len_mat(i - 1, j) >= len_mat(i, j - 1))
                i--;
            else //if (len_mat(i - 1, j) < len_mat(i, j - 1))
                j--;
            // else
            // {
            //     lcs_back_traversal(i - 1, j, str);
            //     lcs_back_traversal(i, j - 1, str);
            //     return;
            // }
        }
    }
}

4 找出所有LCS序列

这里之所以用< set >来存储所有的lcs,是考虑不重复,如果重复问题不在乎的话,使用< vector >也可以。

void LongestCommonSubsequence::lcs_back_traversal(int i, int j, std::string str)
{
    while (i && j)
    {
        if (s1[i - 1] == s2[j - 1])
        {
            str = s1[i - 1] + str;//reverse str
            i--;
            j--;
        }
        else
        {
            if (len_mat(i - 1, j) > len_mat(i, j - 1))
                i--;
            else if (len_mat(i - 1, j) < len_mat(i, j - 1))
                j--;
            else
            {
                //recursion
                lcs_back_traversal(i - 1, j, str);
                lcs_back_traversal(i, j - 1, str);
                return;
            }
        }
    }

    lcs_set.insert(str);
}//! class LongestCommonSubsequence private interface END

5 实现代码附录

#include <iostream>
#include <string>
#include <set>
#include <eigen3/Eigen/Eigen>

#include "lcs.h"
using namespace std;

//! class LongestCommonSubsequence public interface BEGIN
LongestCommonSubsequence::LongestCommonSubsequence(const std::string& _s1, const std::string& _s2): s1(_s1), s2(_s2)
{
    len_mat = Eigen::MatrixXi::Zero(s1.length() + 1, s2.length() + 1);

    //crreat table
    lcs_creat_table();

    //back traversal
    std::string lcs_str("");
    lcs_back_traversal(s1.length(), s2.length(), lcs_str);
}
LongestCommonSubsequence::~LongestCommonSubsequence() {}

void LongestCommonSubsequence::get_lcs_one(std::string& str)
{

    auto i = s1.length();
    auto j = s2.length();

    while (i && j)
    {
        if (s1[i - 1] == s2[j - 1])
        {
            str = s1[i - 1] + str;
            i--;
            j--;
        }
        else
        {
            if (len_mat(i - 1, j) >= len_mat(i, j - 1))
                i--;
            else //if (len_mat(i - 1, j) < len_mat(i, j - 1))
                j--;
            // else
            // {
            //     lcs_back_traversal(i - 1, j, str);
            //     lcs_back_traversal(i, j - 1, str);
            //     return;
            // }
        }
    }
}

void LongestCommonSubsequence::get_lcs_set(std::set<std::string>& strset)
{
    strset = lcs_set;
}

int LongestCommonSubsequence::get_lcs_length()
{
    return len_mat(s1.length(), s2.length());
}

void LongestCommonSubsequence::print_lcs_set()
{
    std::cout << std::endl << "-----lcs set-----" << std::endl;
    std::cout << "length of lcs : " << get_lcs_length() << std::endl;
    std::cout << "size of lcs set: " << lcs_set.size() << std::endl;

    int j = 0;
    for (auto i = lcs_set.begin(); i != lcs_set.end(); i++)
    {
        std::cout << j++ << " " << *i << std::endl;
    }
}//! class LongestCommonSubsequence public interface END

//! class LongestCommonSubsequence private interface BEGIN
void LongestCommonSubsequence::lcs_creat_table()
{
    for (auto i = 1; i <= s1.length(); i++)
    {
        for (auto j = 1; j <= s2.length(); j++)
        {
            //UP_LEFT
            if (s1[i - 1] == s2[j - 1])
                len_mat(i, j) = len_mat(i - 1, j - 1) + 1;
            else
                len_mat(i, j) = std::max(len_mat(i - 1, j), len_mat(i, j - 1));//UP
        }
    }
}

void LongestCommonSubsequence::lcs_back_traversal(int i, int j, std::string str)
{
    while (i && j)
    {
        if (s1[i - 1] == s2[j - 1])
        {
            str = s1[i - 1] + str;
            i--;
            j--;
        }
        else
        {
            if (len_mat(i - 1, j) > len_mat(i, j - 1))
                i--;
            else if (len_mat(i - 1, j) < len_mat(i, j - 1))
                j--;
            else
            {
                lcs_back_traversal(i - 1, j, str);
                lcs_back_traversal(i, j - 1, str);
                return;
            }
        }
    }

    lcs_set.insert(str);
}//! class LongestCommonSubsequence private interface END

6 测试用例

int main(int argc, char const *argv[])
{
    string s1("ABCBDAB");//6
    string s2("BDCABA");//5
    std::set<std::string> lcs_set;

    LongestCommonSubsequence lcs(s1, s2);
    lcs.get_lcs_set(lcs_set);
    lcs.print_lcs_set();

    std::string str;
    lcs.get_lcs_one(str);
    cout << str << endl;

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值