[Python]最长公共子序列 VS 最长公共子串[动态规划]

前言

由于原微软开源的基于古老的perl语言的Rouge依赖环境实在难以搭建,遂跟着Rouge论文的描述自行实现。
Rouge存在N、L、S、W、SU等几大子评估指标。在复现Rouge-L的函数时,便遇到了本博文的问题:求两串的最长公共子序列。

一 参考文献

全文参考均如下博文。

二 最长公共子序列 & 最长公共子串的区别

1、最长公共子序列(Longest Common Subsequence,LCS):在字符串A和字符串B中都出现的序列,且顺序与母串保持一致最长的那个序列。
2、最长公共子串(Longest Common Substring):相比LCS更加严格,序列必须连续出现,即公共的子字符串。

eg: csdnblog与belong,最长公共子序列为blog,最长公共子串为lo。

三 程序设计与实现

3.1 最长公共子序列

def longestCommonSubsequence(seqA, seqB):
    """
    最长公共子序列
    -----------
    [reference] 最长公共子序列与最长公共子串【动态规划】 https://blog.csdn.net/a515557595_xzb/article/details/88296989
    :param seqA:
    :param seqB:
    :return:
    """
    m = len(seqA);
    n = len(seqB);
    init_unit={
        "len":0,
        "lcs":[]
    }
    dp = [[ init_unit ]*(n+1) for i in range(m+1)]; # m+1行, n+1列
    for i in range(0, m+1):
        for j in range(0, n+1):
            if i==0 or j==0:
                dp[i][j] = init_unit;
            elif seqA[i-1] == seqB[j-1]:
                tmp_str = copy.copy((dp[i-1][j-1])["lcs"]);
                tmp_str.append(seqA[i-1]);
                unit = {
                    "len": (dp[i-1][j-1])["len"] + 1,
                    "lcs": tmp_str
                }
                dp[i][j] = unit;
            elif seqA[i-1] != seqB[j-1]:
                if (dp[i-1][j])["len"] > (dp[i][j-1])["len"]: # 存储最长的信息
                    dp[i][j] = dp[i-1][j];
                else:
                    dp[i][j] = dp[i][j-1];
            else:
                pass;
            pass; # end inner for loop
        pass; # end outer for loop
    return dp[m][n];
print( longestCommonSubsequence("GM%$ABG", "gbndGFMABG") ) # {'len': 5, 'lcs': ['G', 'M', 'A', 'B', 'G']}
print( longestCommonSubsequence(["G", "M", "%", "$", "A", "B", "G"], ["g","b", "n", "d", "G", "F", "M", "A", "B","G"] ) ); # {'len': 5, 'lcs': ['G', 'M', 'A', 'B', 'G']}

3.2 最长公共子串

def longestCommonSubstring(strA, strB):
    """
    最长公共子串
    -----------
    [reference] 最长公共子序列与最长公共子串【动态规划】 https://blog.csdn.net/a515557595_xzb/article/details/88296989
    :param strA:
    :param strB:
    :return:
    """
    m = len(strA);
    n = len(strB);
    init_unit={
        "len":0,
        "lcs":[]
    }
    dp = [[ init_unit ]*(n+1) for i in range(m+1)]; # m+1行, n+1列
    result ={
        "len":0, # 记录最长公共子串的长度
        "lcs": []
    };
    for i in range(0, m+1): # 考虑i为0或j为0的情况
        for j in range(0, n+1):
            if i==0 or j==0 or ( strA[i-1] != strB[j-1] ):
                dp[i][j] = init_unit;
            elif strA[i-1] == strB[j-1]:
                tmp_str = copy.copy((dp[i-1][j-1])["lcs"]);
                tmp_str.append(strA[i-1]);
                unit = {
                    "len": (dp[i-1][j-1])["len"] + 1,
                    "lcs": tmp_str
                }
                dp[i][j] = unit;

                if (dp[i][j])["len"] > result["len"]: # 存储最长的信息
                    result = copy.copy( dp[i][j] );
            else:
                pass;
            pass; # end inner for loop
        pass; # end outer for loop
    return result;
print( longestCommonSubstring("GM%$ABG", "gbndGFMABG") ) # {'len': 3, 'lcs': ['A', 'B', 'G']}
print( longestCommonSubstring(["G", "M", "%", "$", "A", "B", "G"], ["g","b", "n", "d", "G", "F", "M", "A", "B","G"] ) ); # {'len': 3, 'lcs': ['A', 'B', 'G']}

四 应用领域

  • 4.1 机器学习 > 自动文本摘要 / 机器翻译 / 机器阅读理解等任务中 > 评估指标 > Rouge-L
    • Rouge-L分类:
      • 句子级: 最长公共子序列
      • 文摘级: Union[多条句子] 最长公共子序列
    • 推荐博文: ROUGE评价方法详解(二)
    • 推荐论文: 《ROUGE: A Package for Automatic Evaluation of Summaries》
posted @ 2019-07-24 01:15  千千寰宇  阅读(646)  评论(0编辑  收藏  举报