最长公共子序列

40 篇文章 0 订阅
6 篇文章 0 订阅

在这里插入图片描述

  1. 返回最长公共子序列的长度
    leetcode 1143
    在这里插入图片描述
class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        m, n = len(text1), len(text2)
        dp = [[0] * (n + 1) for _ in range(m + 1)]

        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if text1[i - 1] == text2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
        return dp[-1][-1]


  1. 返回任意一个最长公共子序列
    https://blog.csdn.net/jingjing_94/article/details/80539403
class Solution:
    def LCS(self,s1,s2):
        c = len(s1)+1
        r = len(s2)+1
        dp = [[0]*c for i in range(r)]
        for i in range(1,r):
            for j in range(1,c):
                if s1[j-1] == s2[i-1]:
                    dp[i][j] = dp[i-1][j-1]+1
                else:
                    dp[i][j] = max(dp[i-1][j],dp[i][j-1])
        maxl = dp[-1][-1]
        print(maxl)
        # 生成最长公共子序列,只返回满足条件的一个
        res = []
        i = r-1
        j = c-1
        while i > 0 and j > 0:
            if s1[j-1] == s2[i-1]:
                res.append(s1[j-1])
                i -= 1
                j -= 1
            else:
                if dp[i-1][j] > dp[i][j-1]:
                    i -= 1
                else:
                    j -= 1
        return ''.join(res[::-1])
 
if __name__ == '__main__':
    p = Solution()
    a = input('enter s1:')
    while a != 'e':
        b = input('enter s2:')
        print(p.LCS(a,b))
        a = input('enter s1:')
  1. 返回所有可能的最长公共子序列集合
    https://blog.csdn.net/zpalyq110/article/details/79994001

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

函数2)回溯公共子串:需要定义一个**全局变量(class的全局变量,定义在所有函数之外)**来存放所有解,并且在分支前记录两个解的公共前缀。

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

// 全局变量
set<string> setOfLCS;

//建立dp数组:记录长度的数组c, 记录路径方向的数组d
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返回一个指向集合的第一个元素的迭代器
    set<string>::iterator beg = setOfLCS.begin();
    for (; beg != setOfLCS.end(); ++beg)
        cout << *beg << endl;
    system("pause");
    return 0;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值