动态规划之最长公共子序列

简介: 给定两个序列x和y,称z是x和y的公共子序列,如果z既是x的子序列,又是y的子序列;最长的公共子序列称作最长公共子序列LCS(longest common subsequence)。解题思路(1)LCS的最优子结构 设zk是xm和yn的一个LCS,则,如果x和y的最后一个元素相同,则z中去掉最后一个元素之后zk-1仍为xm-1和yn-1的LCS。 如果xm!=

给定两个序列x和y,称z是x和y的公共子序列,如果z既是x的子序列,又是y的子序列;最长的公共子序列称作最长公共子序列LCS(longest common subsequence)。

解题思路

(1)LCS的最优子结构
设zk是xm和yn的一个LCS,则,如果x和y的最后一个元素相同,则z中去掉最后一个元素之后zk-1仍为xm-1和yn-1的LCS。
如果xm!=yn,若zk!=xm,则z是xm-1和y的一个LCS,若zk!=yn,则z是xm和yn-1的LCS。

(2)一个递归解
设c[i][j]为序列xi和yj的一个LCS的长度,则有:

expression condition
c[i][j]=0 i=0或j=0
c[i][j]=c[i1][j1]+1 xi=yj且i,j>0
c[i][j]=max(c[i][j1],c[i1][j]) xi!=yj且i,j>0

(3)计算LCS的长度

实现代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int lenLCS(const char *ch1, const char *ch2, int len1, int len2, int **c)
{
    for (int i = 0; i <= len1; i++)
    {
        c[i][0] = 0;
    }
    for (int i = 0; i <= len2; i++)
    {
        c[0][i] = 0;
    }

    for (int i = 1; i <= len1; i++)
    {
        for (int j = 1; j <= len2; j++)
        {
            if (ch1[i-1] == ch2[j-1])
            {
                c[i][j] = c[i-1][j-1] + 1;
            }
            else
            {
                if (c[i-1][j] >= c[i][j-1])
                {
                    c[i][j] = c[i-1][j];
                }
                else
                {
                    c[i][j] = c[i][j-1];
                }
            }
        }
    }

//    for (int i = 0; i <= len1; i++)
//        for (int j = 0; j <= len2; j++)
//            if (j == len2) printf("%d\n", c[i][j]);
//            else printf("%d ", c[i][j]);

    return c[len1][len2];
}

void printLCS(const char *ch1, const char* ch2, int len1, int len2, int **c)
{
    int i = len1;
    int j = len2;
    while (c[i][j] > 0)
    {
        if (ch1[i-1] == ch2[j-1])
        {
            cout<<ch1[i-1];
            i--;
            j--;
        }
        else
        {
            if (c[i][j] == c[i-1][j])
            {
                i--;
            }
            else
            {
                j--;
            }
        }
    }
}

int main()
{
    char *ch1 = "ACCGGTCGAGTGCGCGGAAGCCGGCCGAA";
    char *ch2 = "GTCGTTCGGAATGCCGTTGCTCTGTAAA";
    int len1 = strlen(ch1);
    int len2 = strlen(ch2);
    int **c = new int*[len1 + 1];
    for (int i = 0; i <= len1; i++)
    {
        c[i] = new int[len2 + 1];
    }

    cout<<lenLCS(ch1, ch2, len1, len2, c)<<endl;
    printLCS(ch1, ch2, len1, len2, c);

    for (int i = 0; i <= len1; i++)
    {
        delete [] c[i];
    }
    delete [] c;
    return 0;
}

不连续情况的转移方程:
这里写图片描述
扩展到连续情况,转移方程为:
这里写图片描述
实现代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int fun(char *ch1, char *ch2, int len1, int len2, int **c)
{
    for (int i = 0; i <= len1; i++)
    {
        c[i][0] = 0;
    }
    for (int j = 0; j <= len2; j++)
    {
        c[0][j] = 0;
    }

    int maxlen = 0;
    for (int i = 1; i <= len1; i++)
    {
        for (int j = 1; j <= len2; j++)
        {
            if (ch1[i-1] == ch2[j-1])
            {
                c[i][j] = c[i-1][j-1] + 1;
            }
            else
            {
                c[i][j] = 0;
            }

            maxlen = max(maxlen, c[i][j]);
        }
    }

    return maxlen;
}

int main()
{
    char *ch1 = "acaccbabb";
    char *ch2 = "acbac";
    int len1 = strlen(ch1);
    int len2 = strlen(ch2);
    int **c = new int*[len1 + 1];
    for (int i = 0; i <= len1; i++)
    {
        c[i] = new int[len2 + 1];
    }
    int maxlen = fun(ch1, ch2, len1, len2, c);
    printf("The max length is : %d\n", maxlen);

    for (int i = 0; i <= len1; i++)
    {
        delete [] c[i];
    }
    delete [] c;
}
目录
相关文章
|
应用服务中间件
SpringMVC中的@RequestMapping注解的详细介绍过程~
SpringMVC中的@RequestMapping注解的详细介绍过程~
218 0
|
12月前
|
Java Spring
Spring Boot的核心注解是哪个?他由哪几个注解组成的?
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 : ● @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能; ● @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项 ● @ComponentScan:Spring组件扫描
|
域名解析 网络协议 数据安全/隐私保护
TCP/IP配置
【10月更文挑战第20天】TCP/IP配置
739 1
|
算法 Python
KMP
【7月更文挑战第7天】
939 5
|
XML Java 应用服务中间件
SpringBoot启动流程解析
SpringBoot启动流程解析
358 0
|
前端开发
React中的无限渲染问题总结
React中的无限渲染问题总结 前言 无限渲染情况汇总分析 第一种情况 第二种情况 第三种情况:state和setState分别在useEffect的依赖和回调中(前两种只与useState有关) 第四种:缺失依赖 第五种:函数(对象)作为依赖 第六种:将数组(对象)作为依赖 第七种:将对象作为依赖 总结 参考
877 0
React中的无限渲染问题总结
|
网络协议 Linux Shell
技术笔记:Linux中的两种守护进程standalone和xinetd
技术笔记:Linux中的两种守护进程standalone和xinetd
442 0
|
数据管理 Java
Spigot开发中的事件与监听器的关系
在Spigot插件开发中,监听器(Listener)是一个非常重要的概念。它们允许你捕捉和处理各种游戏事件,使你的插件能够对玩家的行为、游戏环境的变化等做出响应。本文将详细介绍监听器是什么、它们的用途,并通过一个代码示例展示如何使用监听器。
216 0
|
SQL Java 数据库连接
Java开发者必知:JDBC连接数据库的“三大法宝”
Java开发者必知:JDBC连接数据库的“三大法宝”
158 7
【中级软件设计师】—(下午题)试题三精讲总结(四十二)
【中级软件设计师】—(下午题)试题三精讲总结(四十二)

热门文章

最新文章