Java基于动态规划法实现求最长公共子序列及最长公共子字符串示例

Java基于动态规划法实现求最长公共子序列及最长公共子字符串示例攻略

什么是最长公共子序列?

两个序列 X 和 Y 的“公共子序列”,是指存在一个序列 Z,Z 中元素既在 X 中,也在 Y 中,在 X 和 Y 中出现的次序分别相同,且 Z 的长度最大。例如序列“12345”和“1245”的公共子序列有“12”、“145”等,其中“145”最长,长度为 3,即为“12345”和“1245”的最长公共子序列(Largest Common Subsequence,LCS)。

什么是最长公共子串?

两个字符串 X 和 Y 的“公共子串”,是指在 X 和 Y 中都出现过的连续字符串。例如字符串“Hello World”和“Hella World”的公共子串有“Hell”、“ello”等,其中“ello”最长,长度为 4,即为“Hello World”和“Hella World”的最长公共子串(Longest Common Substring,LCS)。

如何求最长公共子序列?

我们可以利用动态规划(Dynamic Programming,DP)来解决这个问题。

动态规划法解决问题的一般步骤:

  1. 问题转化:将原问题转化为子问题。
  2. 定义状态:定义状态方程。
  3. 确定状态转移方程:根据子问题之间的关系,确定通项公式。
  4. 分析复杂性:定义好状态和状态转移方程后,问题的时间复杂度通常比较容易分析。

最长公共子序列-算法分析

众所周知,两个序列的最长公共子序列问题可以用动态规划算法求解。具体思想是,设序列 X 和 Y 的长度分别为 m 和 n,则先用 m 行 n 列的矩阵 dp 存储 X 和 Y 之间任意部分的 LCS 长度,其中 dp[i][j] 表示 X[0~i] 和 Y[0~j] 的 LCS 的长度。接下来,序列X和Y的任何LCS都是矩阵 dp[m][n] 中的数字。

例如,X = “fasdugnisarefhadseo” ,Y = “sduguarsdewq” ,LCS 就是 “sdug”,长度为 4。

实现如下:

public static String LCSLength(String str1, String str2) throws Exception {
        if (str1.isEmpty() || str2.isEmpty()){
            throw new Exception("cannot input null...");
        }

        int len1 = str1.length();
        int len2 = str2.length();
        int[][] LCSLength = new int[len1 + 1][len2 + 1];

        for (int i = 0; i <= len1; i++) {
            for (int j = 0; j <= len2; j++) {
                if (i == 0 || j == 0) {
                    LCSLength[i][j] = 0;
                } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    LCSLength[i][j] = LCSLength[i - 1][j - 1] + 1;
                } else {
                    LCSLength[i][j] = Math.max(LCSLength[i - 1][j], LCSLength[i][j - 1]);
                }
            }
        }

        int index = LCSLength[len1][len2];
        char[] lcs = new char[index];
        int i = len1, j = len2;
        while (i > 0 && j > 0) {
            if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                lcs[--index] = str1.charAt(i - 1);
                i--;
                j--;
            } else if (LCSLength[i - 1][j] > LCSLength[i][j - 1]) {
                i--;
            } else {
                j--;
            }
        }
        return new String(lcs);
    }

最长公共子串-算法分析

在实现最长公共子串的时候,我们需要将问题转化为动态规划问题。我们需要用矩阵 dp 记录当前考虑的任意两个子串的最长公共子串长度,其中 dp[i][j] 表示 str1 的前 i 个字符和 str2 的前 j 个字符的最长公共子串长度。由于最长公共子串要求连续,所以在考虑 str1 和 str2 的第 i 个和第 j 个字符的时候,我们如果两者相等,就可以根据 dp[i - 1][j - 1] + 1 更新当前的 dp[i][j],否则 dp[i][j] = 0。

例如,str1 = “fasdugnisarefhadseo” ,str2 = “sduguarsdewq” ,LCS 就是 “sdug”,长度为 4。

实现如下:

class Main {
    public static String LCSubstring(String str1, String str2) throws Exception {
        if (str1.isEmpty() || str2.isEmpty()){
            throw new Exception("cannot input null...");
        }
        int[][] dp = new int[str1.length() + 1][str2.length() + 1];
        int maxLen = 0, maxEnd = str1.length(), index = str1.length();
        for (int i = 1; i <= str1.length(); i++) {
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                if (dp[i][j] > maxLen) {
                    maxLen = dp[i][j];
                    maxEnd = i;
                }
            }
        }
        return str1.substring(maxEnd - maxLen, maxEnd);
    }
}

示例说明

示例 1:求两个字符串的最长公共子序列

输入:

String str1 = "fasdugnisarefhadseo";
String str2 = "sduguarsdewq";
String lcs = LCSLength(str1, str2);
System.out.println(lcs);

输出:

sdug

示例 2:求两个字符串的最长公共子串

输入:

String str1 = "fasdugnisarefhadseo";
String str2 = "sduguarsdewq";
String lcs = LCSubstring(str1, str2);
System.out.println(lcs);

输出:

sdug

总结

以上就是动态规划求解最长公共子序列和最长公共子串的完整攻略,其中给出了两个示例分别演示了如何使用代码求解最长公共子序列和最长公共子串。在实际编程中,我们可以利用动态规划算法解决这个问题,使用矩阵 dp 记录当前问题的状态和解,用通用公式进行状态转移,从而得出最优解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java基于动态规划法实现求最长公共子序列及最长公共子字符串示例 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • java实现简单的搜索引擎

    一、准备工作 在开始实现搜索引擎之前,需要准备以下工作: 编译环境:需要在本地安装JDK环境,并配置好对应的环境变量。 Maven管理工具:Maven是一个Java项目管理工具,能够自动下载所需的依赖库,并管理项目的编译、测试、打包等过程。 Lucene搜索引擎库:Lucene是一种高效的文本搜索引擎库,它提供了全文检索、模糊搜索、分词等功能,是实现搜索引擎…

    Java 2023年5月18日
    00
  • Java项目的目录结构详解

    下面我来详细讲解Java项目的目录结构: 1. 为什么需要规范的目录结构 在一个Java项目中使用规范的目录结构,可以帮助我们清晰地组织我们写的代码,管理项目中的不同模块,提高我们的项目管理和团队协作效率。 2. Java项目的目录结构 下面是Java项目的目录结构示意图: project ├── src │ ├── main │ │ ├── java # …

    Java 2023年5月20日
    00
  • JSP常见的文件操作小结

    JSP常见的文件操作小结 在JSP开发中,文件的操作是比较常见的一个任务,下面整理了关于JSP常见文件操作的攻略。 1. 文件的读取 1.1 读取文本文件 读取文本文件的方法非常简单,只需要使用Java IO库中的BufferedReader来读取文件即可。示例如下: <% String fileName = "example.txt&quo…

    Java 2023年6月15日
    00
  • 01-三层架构之查询数据库数据

    一、后台操作流程 1.创建数据库 CREATE DATABASE wyy_music; USE wyy_music; DROP TABLE IF EXISTS `tb_music`; CREATE TABLE `tb_music` ( `music_id` INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT, — 歌曲I…

    Java 2023年5月8日
    00
  • Java文件上传下载、邮件收发实例代码

    Java文件上传下载及邮件收发是Java程序开发中常用的功能,本文将为大家介绍Java文件上传下载及邮件收发的实例代码,帮助大家更好地掌握Java编程中这些常见功能的实现。 文件上传下载 上传文件 文件上传是Web应用开发中常见的功能之一。以下是一个文件上传的示例代码: @PostMapping("/upload") public Str…

    Java 2023年6月15日
    00
  • JVM调优笔记(一)–Nacos GC引发的服务批量下线问题

    故障背景 线上批量发服务下线的告警邮件,偶发nacos连接超时。采用了spring boot admin(以下称sba)进行服务监控。 原因分析 因为sba服务是基于nacos对其它服务进行监控,所以遇到这个问题,第一怀疑对象是nacos发生问题,但不清楚具体是什么问题。由于服务过一段事件会恢复,所以nacos肯定是没有挂掉的,那么排查方向应该是针对naco…

    Java 2023年4月23日
    00
  • jsp与sql语句的混合使用示例

    下面是关于“JSP与SQL语句的混合使用示例”的攻略: 一、JSP页面中引用SQL语句的示例 在JSP页面中获取数据库中的数据,我们可以使用Java的JDBC或ORM框架,也可以使用JSP的内置对象——JDBC Pool和JSTL标签库来完成。下面是一个简单的示例,它使用的是JDBC Pool和JSTL标签库: 首先,在web.xml文件中配置数据源: &l…

    Java 2023年6月15日
    00
  • Linux环境搭建之安装/配置Tomcat的方法

    关于“Linux环境搭建之安装/配置Tomcat的方法”的攻略,我给您提供以下步骤及示例。 安装Java Tomcat依赖Java运行环境,所以首先需要安装Java: # 添加yum源 sudo yum install -y java-1.8.0-openjdk-devel # 设置Java环境变量 export JAVA_HOME=/usr/lib/jvm…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部