首页 > 编程语言 >最长公共子序列(线性dp)-java

最长公共子序列(线性dp)-java

时间:2024-04-09 20:04:27浏览次数:31  
标签:java dp 字符串 序列 线性 new 最长 个字符

本文主要来描述两个字符串的最长公共子序列问题

文章目录

前言

一、最长公共子序列

二、算法思路

1.dp[i][j]的四种情况

2. dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]的关系

3.dp数组的状态转移方程

 4.dp数组具体如下

三、代码如下

1.代码如下(示例):

2.读入数据

3.代码运行结果

总结


前言

本文主要来描述两个字符串的最长公共子序列问题


提示:以下是本篇文章正文内容,下面案例可供参考

一、最长公共子序列

定两个长度分别为 N 和 M 的字符串 A 和 B,求既是 A 的子序列又是 B的子序列的字符串长度最长是多少。

二、算法思路

1.dp[i][j]的四种情况

引入字符数组a和b,字符数组a存入字符串A,字符数组b存入字符串B。

我们引入二维数组dp,dp[i][j]表示的含义为表示所有在第一个字符串中出现的前i个字母即a[i]和第二个字符串中出现的前j个字母即b[j]的公共子序列。

图1.1思路模拟 

dp[i][j]通常是由以下4种情况构成

  • 当a[i]和b[j]都不取。即取字符串A前i 个字符和字符串B的前j个字符的最长公共子序列的长度dp[i-1]dp[j-1]
  • 当a[i]不取,b[j]取。而dp[i-1][j]表示的是字符串A的前i-1个字符和字符串B的前j个字符的最长公共子序列,其中可能包括字符串B的第j个字符也可能不包括字符串B的第j个字符。
  • 当a[i]取,b[j]不取。dp[i][j-1]表示的字符串A的前i个字符和字符串B的前j-1的字符的最长公共子序列,其中可能包括字符串A的第i个字符也可能不包括字符串A的第j个字符。
  • 当a[i]和b[j]都取,即字符串A的第i个字符和字符串B的第j个字符相等时,那么就代表我们取字符串A的前i-1个字符和字符串B的前j-1个字符的最长公共子序列的长度(即dp[i-1][j-1])加上1,既可以得到此时dp[i][j]的值,即dp[i][j] = dp[i-1]dp[j-1]+1

2. dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]的关系

图2.1dp[i-1][j]、dp[i][j-1]和dp[i-1][j-1]的关系 

dp[i-1][j]表示 字符串A的前i-1个字符和字符串B的前j个字符的最长公共子序列。

dp[i][j-1]表示的字符串A的前i个字符和字符串B的前j-1的字符的最长公共子序列

那么dp[i-1][j]和dp[i][j-1]的重复的部分就表示字符串A的前i-1个字符和字符串B的前j-1个字符串的最长公共子序列即dp[i-1][j-1]。(不取字符串A的第i个字符和字符串B的第j个字符)

3.dp数组的状态转移方程

因为我们dp[i][j]表示的值是上述所描述的4种情况取最大值,那么我们就不必再取dp[i-1][j-1]的值,因为dp[i-1][j]的值和dp[i][j-1]的值肯定都比dp[i-1][j-1]的值大,dp[i-1][j-1]分别是dp[i-1][j]和dp[i][j-1]的子集。

当a[i] != b[j]时:

dp[i][j] = max(dp[i-1][j],dp[i][j-1])

当a[i] = b[j]时:

dp[i][j] = dp[i-1][j-1]+1

 4.dp数组具体如下

我们以测试样例字符串acbd和字符串abedc为例,dp数组各个值如下:

0 0 0 0 0 0 
0 1 1 1 1 1 
0 1 1 1 1 2 
0 1 2 2 2 2 
0 1 2 2 3 3

三、代码如下

1.代码如下(示例):


import java.io.*;
import java.util.Scanner;

public class 最长公共子序列 {
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static void main(String[] args) throws Exception{
        Scanner sc =new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int n = sc.nextInt();
        int m = sc.nextInt();
        String a = sc.next();
        String b = sc.next();
        char[] Achar = new char[1010];
        char[] Bchar = new char[1010];
        for(int i = 1;i <= n;i++){
            Achar[i] = a.charAt(i-1);
        }
        for(int i = 1;i <= m;i++){
            Bchar[i] = b.charAt(i-1);
        }
        int[][] dp = new int[1010][1010];
        for(int i = 1;i <= n;i++){
            for(int j = 1; j<= m;j++){
                dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
                if(Achar[i] == Bchar[j]){
                    dp[i][j] = Math.max(dp[i][j],dp[i-1][j-1]+1);
                }
            }
        }
        pw.println(dp[n][m]);
        pw.flush();
    }
    public static int nextInt()throws Exception{
        st.nextToken();
        return (int)st.nval;
    }
}

2.读入数据

4 5
acbd
abedc

3.代码运行结果

3

即acbd和abedc的最长公共子序列为abd,长度为3 


总结

只要弄懂dp[i][j]、dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]各个值之间的关系和状态转移方程的由来即可解决最长公共子序列问题。

标签:java,dp,字符串,序列,线性,new,最长,个字符
From: https://blog.csdn.net/m0_63267251/article/details/137526076

相关文章

  • Java基础知识-面向对象编程(OOP)-Java集合框架-多线程和并发-Spring框架
    Java基础知识:Java的四种基本数据类型是:byte、short、int、long(整数类型)、float、double(浮点类型)、char(字符类型)、boolean(布尔类型)。它们之间的区别主要在于占用的内存大小和表示范围不同。Java中的String是不可变的意味着一旦String对象被创建,它的值就不能被修改。这意味着St......
  • Java IO与NIO-Java内存管理-Java虚拟机(JVM)-Java网络编程-Java注解(Annotation)
    JavaIO与NIO:请解释Java中的IO(Input/Output)和NIO(NewInput/Output)的区别是什么?它们各自的优势是什么?答案:Java中的IO是基于流(Stream)的方式进行输入输出操作,而NIO则是基于通道(Channel)和缓冲区(Buffer)的方式进行输入输出操作。NIO相比于IO具有非阻塞IO、选择器(Selector)和内存映......
  • Java——继承(含习题)
    继承的概念定义面向对象的继承,指在由一般类和特殊类形成的“一般-特殊”之间的类结构中,把一般类和所有特殊类都共同具有的属性和操作一次性地在一般类中进行定义,特殊类不再重复定义一般类已经定义的属性和操作,特殊类自动拥有一般类(以及所有更上层的一般类)定义的属性和操作......
  • Java登陆第四十一天——Axios
    Vue推荐使用axios来完成ajax请求。axios中文文档AxiosAxios是一款基于Promise,用于发送HTTP请求和处理HTTP响应的工具库。内部也是使用原生的ajax对象发送HTTP请求。所以,在使用它前需要导入依赖。npminstallaxios提供了一个函数:axios()语法格式如下://查看源码,默认......
  • Java面向对象进阶(二)
    day02——面向对象高级今天我们继续学习面向对象的语法知识,我们今天学习的主要内容是:继承,多态、抽象、接口。学会这些语法知识,可以让我们编写代码更灵活,代码的复用性更高。2.1继承快速入门各位同学,我们继续学习面向对象相关内容。面向对象编程之所以能够能够被广大开发......
  • 类鸡兔同笼(java)
    【题目】共有50枚硬币,可能包括4种类型:1元,5角,1角,5分。已知总价值为20元。求各种硬币的数量。【代码】publicclassTest12{publicstaticvoidmain(String[]args){//i是1元j是5角k是1角l是5分intsum=0;inti=0,j=0,k=0,l......
  • java 对List<Map<String, Object>>遍历
    在Java中,遍历List<Map<String,Object>>可以通过多种方式来实现。以下是一些常见的方法:使用for-each循环javaList<Map<String,Object>>list=//初始化你的Listfor(Map<String,Object>map:list){for(Map.Entry<String,Object>entry:map.entrySet()){......
  • JAVA 处理目录下及子目录下 图片压缩和图片加水印
    JAVA处理目录下及子目录下图片压缩压缩需要用到其他jar包<dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.14</version></dependency>处理目录下及子目录下图片压缩importnet.coobird.thum......
  • java基础的一小点
    java文件启动的一套流程:.java---通过编译器javac---->.class---经过解释器&JIT--->机器码--->电脑可识别运行 一般而言,不是开发的安个jre就行,但类似于jsp编译就需要jdk的开发工具。JIT(justintime)即使编译器,可对热点代码直接编译。所以说比解释性语言快些、解释和编译型语......
  • java -动态sql语句
    数据库算法双子针、动态规划、二分查找、贪心算法、深度优先搜索、字符串、递归、字典树、排序、链表等元素作用描述if......