动态规划——多样本位置全对应的尝试模型,两个字符串的最长公共子序列问题

简介: 动态规划——多样本位置全对应的尝试模型,两个字符串的最长公共子序列问题

题目

给定两个字符串str1和str2,str1="a123bc",str2="12dea3f"。那么这两个字符串的最长公共子序列的长度是多少?

很明显,根据这个题目的类型再加上我们以往的经验,我们可以根据题目给出的两个样本做出一个二维表:

int[][] dp=new int[str1.length][str2.length];

在这里插入图片描述
那么,这个表的含义是什么呢?

表中任意一个格子(dpi),就代表str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度是多少。因为我们要求的问题是两个字符串的整体的最长公共子序列有多长。

那么把右下角的格子算出来就是我们要求的主问题。

在这里插入图片描述
记住这一点:dpi代表str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度!!!

1)填dp0的值,两个字符串都只拿第一个字符比较,相同就说明最长公共子序列长度为1;否则为0

dp[0][0]=str1[0]==str2[0]?1:0;

2)填第0行数据:str1只拿第一个字符,和str2整体比较

for(int j=1; j<str2.length; j++) {
    dp[0][j]=Math.max(dp[0][j-1], str2[j]==str1[0]?1:0);
}

3)填第0列数据:str2只拿第一个字符,和str1整体比较

for(int i=1; i<str1.length; i++) {
    dp[i][0]=Math.max(dp[i-1][0],str1[i]==str2[0]?1:0);
}

在这里插入图片描述
接下来,任何普遍位置如何尝试呢?有4种可能性:

1)两个字符串的最长公共子序列既不以str1[i]结尾,也不以str2[j]结尾,比如"a123b"和"c123e"的最长公共子序列是"123"。也就是说,str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度等同于str1[0]到str1[i-1]和str2[0]到str2[j-1]的最长公共子序列的长度。也即是说,任何一个普遍位置的格子有可能依赖其左上角的格子!!!
在这里插入图片描述

2)两个字符串的最长公共子序列以str1[i]结尾,但是不以str2[j]结尾,比如"ab123"和"c123ef"的最长公共子序列是"123"。也就是说,str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度等同于str1[0]到str1[i]和str2[0]到str2[j-1]的最长公共子序列的长度。也即是说,任何一个普遍位置的格子有可能依赖其左边的格子!!!
在这里插入图片描述
3)两个字符串的最长公共子序列不以str1[i]结尾,但是以str2[j]结尾,比如"a123bc"和"ef123"的最长公共子序列是"123"。也就是说,str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度等同于str1[0]到str1[i-1]和str2[0]到str2[j]的最长公共子序列的长度。也即是说,任何一个普遍位置的格子有可能依赖其右上角的格子!!!
在这里插入图片描述
4)两个字符串的最长公共子序列既以str1[i]结尾,也以str2[j]结尾,比如"ab12c3"和"d12ef3"的最长公共子序列是"123"。但是前提条件必须是str1[i]==str2[j]。也就是说,str1[0]到str1[i]和str2[0]到str2[j]的最长公共子序列的长度等同于str1[0]到str1[i-1]和str2[0]到str2[j-1]的最长公共子序列的长度再加1!!!

除此以外,再无其它可能性。这种可能性组织方式的关键是最长公共子序列最后一个字符在哪个位置。

完整代码:

package com.harrison.class13;

public class Code08_LongestCommonSubsequence {
    public static int lcs(char[] str1,char[] str2) {
        int[][] dp=new int[str1.length][str2.length];
        dp[0][0]=str1[0]==str2[0]?1:0;
        // 填第0列的值
        for(int i=1; i<str1.length; i++) {
            dp[i][0]=Math.max(dp[i-1][0],str1[i]==str2[0]?1:0);
        }
        // 填第0行的值
        for(int j=1; j<str2.length; j++) {
            dp[0][j]=Math.max(dp[0][j-1], str2[j]==str1[0]?1:0);
        }
        for(int i=1; i<str1.length; i++) {
            for(int j=1; j<str2.length; j++) {
                dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                // 如果if没中,为什么可能性1(dp[i-1][j-1])可以省略
                // 因为可能性2和3必然会覆盖可能性1
                if(str1[i]==str2[j]) {
                    dp[i][j]=Math.max(dp[i][j], dp[i-1][j-1]+1);
                }
            }
        }
        return dp[str1.length-1][str2.length-1];
    }
    
    public static void main(String[] args) {
        System.out.println(lcs("a123bc".toCharArray(),"12dea3f".toCharArray()));
    }
}
相关文章
|
4月前
|
算法 测试技术 C++
【动态规划】【字符串】1092. 最短公共超序列
【动态规划】【字符串】1092. 最短公共超序列
|
4月前
|
机器学习/深度学习 算法 测试技术
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
|
3月前
|
存储 算法 数据可视化
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
LeetCode 132题详解:使用动态规划与中心扩展法解决分割回文串 II 的最少分割次数问题
|
3月前
|
算法
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
|
4月前
|
算法 索引
【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串
经过这两道题目的书写,相信大家一定深刻认识到了滑动窗口的使用方法!!! 下面请大家继续刷题吧!!!
28 0
|
4月前
|
人工智能 自然语言处理 算法
【动态规划】【字符串】【前缀和】1639通过给定词典构造目标字符串的方案数
【动态规划】【字符串】【前缀和】1639通过给定词典构造目标字符串的方案数
|
4月前
|
算法 JavaScript 测试技术
动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本
动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本
|
4月前
|
算法 Java C++
数据结构与算法面试题:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。(提示:使用动态规划或者中心扩散)
数据结构与算法面试题:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。(提示:使用动态规划或者中心扩散)
70 0
|
4月前
|
算法 Java
给定一个字符串数组,如何找到其中最长的回文子串? 要求:编写一个Java函数,输入一个字符串数组,输出其中最长的回文子串。要求时间复杂度为O(n^2)。可以考虑使用动态规划或中心扩展的方法来优化算法。
给定一个字符串数组,如何找到其中最长的回文子串? 要求:编写一个Java函数,输入一个字符串数组,输出其中最长的回文子串。要求时间复杂度为O(n^2)。可以考虑使用动态规划或中心扩展的方法来优化算法。
75 1
|
4月前
|
算法 程序员 索引
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
87 0