1143.最长公共子序列

文章目录

  • 1143.最长公共子序列
    • 一、题目描述
    • 二、方法一:暴力法
    • 三、方法二、动态规划
    • 四、补充:打印输出最长公共子串
    • 五:心得体会

1143. 最长公共子序列

一、题目描述

示例 1:

输入:text1 = "abcde", text2 = "ace"
输出:3解释:最长公共子序列是 "ace",它的长度为 3。

示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3解释:最长公共子序列是 "abc",它的长度为 3。

示例 3:

输入:text1 = "abc", text2 = "def"
输出:0解释:两个字符串没有公共子序列,返回 0。

二、方法一:暴力法

​ 一开始打算用最笨的方法,遍历列举所有情况,思路是这样的:

  • 先筛选出哪个是长串t1,哪个是短串t2,记i,j分别是t1,t2遍历的下标。
  • 如果t1[i] == t2[j],则i,j同时移动,判断接下来是否存在相同字符
  • 如果t1[i] != t2[j],则i移动,j不动。
  • 如果i到达了串尾,j还没到,则i=0重新再来遍历一遍

​ 我发现我没有逻辑依据,就凭空的移动i,j两个指针,最后无法满足大部分情况,在第7个例子:“ezupkr” “ubmrapg” 跪下了。

最长公共子串字符串匹配不太相同,最长公共子串保证在串A和串B中,存在最长的公共的字符顺序。这就使得在不做备忘录的情况下,依次遍历似乎找不到这个公共序列

//暴力法
public int longestCommonSubsequence(String text1, String text2) {if(text1.length() == 0 || text2.length() == 0){return 0;}//得到最长最短串String t1 = text1.length() >= text2.length() ? text1 : text2;String t2 = text1.length() < text2.length() ? text1 : text2;int result = 0;int length = t1.length();  //最长的串长度int length1 = t2.length();   //最短的串长度int i = 0;  //最长串每趟遍历的下标int j = 0;  //最短串每趟遍历的下标//只有当最短串遍历完才算结束  eg: "psnw","vozsh", eg:"ezupkr" "ubmrapg", eg:"acace","abcde" //短串遍历完时,长串也必须遍历完 eg: "abcde","ace"//"ezupkr","ubmrapg"while(j < (length1 - 1) || i < length){// System.out.println(i + "...." + j);//如果i已经遍历到头,先判断j是否到头//如果j未到头,则i从0开始,短串j移动,启动新一轮的遍历//如果j到头,,则比较i与j字符是否相等,再结束遍历if(i == (length - 1)){if(j < (length1 - 1)){i = 0;j++; }else{if(t1.charAt(i) == t2.charAt(j)){result += 1;}i++;j++;}}else{//如果i与j字符相同,则result + 1, 长短串同时向后遍历一个单位if(t1.charAt(i) == t2.charAt(j)){i++;j++;result += 1;}//如果i与j字符不同,则长串向后遍历一个单位,短串不动else{i++;}}}return result;
}

三、方法二、动态规划

​ 我理解的动态规划是指大问题的解依赖于子问题的解,第i个状态依赖于第i-1个状态,然而这道题是两个字符串,所以第[i,j]状态依赖于第[i-1,j]和[i, j - 1]的状态,主要是这个状态转移方程怎么找的问题

分析1:

  • 如果t1[ i ] != t2[j] ,则dp[ i ][ j ] = max(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ]);
  • 如果t1[ i ] == t2[j] ,则dp[ i ][ j ] = max(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ]) + 1;

这时会发现这种方法在在**“abcde”,“ace"没问题,但在"bsbininm”,“jmjkbkjkv”**上出现问题

输入:"bsbininm","jmjkbkjkv"
错误输出:2
正确输出:1

分析2:

​ 如果text1[i] != text2[j],dp[ i ][ j ]依赖于上一个状态dp[i-1][j-1]。上一个状态是没加入要比较的字符text1[i],text2[j]的text1,text2子串,斜上方是上一个状态,不是max(左方,上方)

  • 如果t1[ i ] != t2[j] ,则dp[ i ][ j ] = dp[ i - 1 ][ j - 1];
  • 如果t1[ i ] == t2[j] ,则dp[ i ][ j ] = dp[ i - 1 ][ j - 1] + 1;

这时会发现这种方法在**“bsbininm”,“jmjkbkjkv"没问题,在"abcde”,“ace”**上出现问题

输入:"abcde","ace"
错误输出:1
正确输出:3

分析3:

  • 如果t1[ i ] != t2[j] ,则dp[ i ][ j ] = max(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ]);
  • 如果t1[ i ] == t2[j] ,则dp[ i ][ j ] = min(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ]) + 1;

这时会发现这种方法在**“bsbininm”,“jmjkbkjkv”** 或者 “abcde”,“ace"上没问题,但在"bmvcnwrmxcfcxabkxcvgbozmpspsbenazglyxkpibgzq”,**“bmpmlstotylonkvmhqjyxmnqzctonqtobahcrcbibgzgx”**上出现问题

输入:"bmvcnwrmxcfcxabkxcvgbozmpspsbenazglyxkpibgzq""bmpmlstotylonkvmhqjyxmnqzctonqtobahcrcbibgzgx"
错误输出:14
正确输出:13

分析4:

考虑三个方向,及dp[i-1][j],dp[i][j-1],dp[i-1][j-1]

  • 如果t1[ i ] != t2[j] ,则dp[ i ][ j ] = max(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ],dp[i-1][j-1]);
  • 如果t1[ i ] == t2[j] ,则dp[ i ][ j ] = min(dp[ i - 1 ][ j ],dp[ i ][ j - 1 ],dp[i-1][j-1]) + 1;

参考题解 https://leetcode-cn.com/problems/longest-common-subsequence/solution/dong-tai-gui-hua-zhi-zui-chang-gong-gong-zi-xu-lie/


代码如下:

class Solution {public int longestCommonSubsequence(String text1, String text2) {if(text1.length() == 0 || text2.length() == 0) return 0;//维护一个二维数组,由于第i行,j列依赖与i-1,j-1的状态,所以预留出多余的第一列,第一行,且为0int dp[][] = new int[text1.length() + 1][text2.length() + 1];// //第1列全为0// for(int i = 0; i < dp.length; i++){//     dp[i][0] = 0;// }//  //第1行全为0//  for(int i = 0; i < dp[0].length; i++){//     dp[0][i] = 0;// }int max = 0;int max_i = 0, max_j = 0;for(int i = 1; i < dp.length; i++){for(int j = 1; j < dp[0].length; j++){//如果text1[i] != text2[j],则dp[i][j]依赖于上一个状态,及dp[i-1][j],dp[i][j-1],dp[i-1][j-1]三者选最大if(text1.charAt(i - 1) != text2.charAt(j - 1)){dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);dp[i][j] = Math.max(dp[i][j],dp[i - 1][j - 1]);}//如果text1[i] == text2[j],则dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]) + 1else{int min = Math.min(dp[i-1][j],dp[i][j-1]);min = Math.min(min, dp[i-1][j-1]);dp[i][j] = min + 1;}if(max < dp[i][j]){max = dp[i][j];max_i = i;max_j = j;}}}return max;}

Accepted

  • 38/38 cases passed (18 ms)
  • Your runtime beats 21.36 % of java submissions
  • Your memory usage beats 8.33 % of java submissions (43.5 MB)

四、补充:打印输出最长公共子串

​ 从最大值开始,记录坐标,采用逆推法输出最长公共子串

  • 如果text1[i] != text2[j],找到三个方向的最大值,如果相等,默认斜向上
  • 如果text1[i] == text2[j],先拼接sub,找到三个方向的最小值,默认斜向上
if(max != 0){String sub = "";  /*** 逆推法:* 如果text1[i] != text2[j],找到三个方向的最大值* 如果text1[i] == text2[j],先拼接sub,找到三个方向的最小值,默认斜向上*/int i = max_i, j = max_j;//判断最大值max是从哪里变过来的,注意边界处理while(i >= 1 && j >= 1){int a1 = dp[i-1][j]; //上方int a2 = dp[i][j-1]; //左方int a3 = dp[i-1][j-1]; //斜上方if(text1.charAt(i - 1) == text2.charAt(j - 1)){sub += text1.charAt(i - 1);//选最小值if(a1 < a2){if(a1 < a3){i = i-1;}else{i = i-1;j = j-1;}}else{if(a2 < a3){j = j-1;}//如果三个数相等,走斜上方else{i = i-1;j = j-1;}}}else{//选最大值if(a1 > a2){if(a1 > a3){i = i-1;}else{i = i-1;j = j-1;}}else{if(a2 > a3){j = j-1;}//如果三个数相等,走斜上方else{i = i-1;j = j-1;}}}}//反向打印subfor(int k = sub.length() -1; k >= 0; k--){System.out.print(sub.charAt(k));}
}

以第36个例子为例

"bmvcnwrmxcfcxabkxcvgbozmpspsbenazglyxkpibgzq"
"bmpmlstotylonkvmhqjyxmnqzctonqtobahcrcbibgzgx"Output (8 ms)
13Expected Answer
13Stdout
bmnmxcbcbbzgx

五:心得体会

  • 之前了解到动态规划的题一开始用暴力法来解,做题顺序如下:暴力的递归解法 -> 带备忘录的递归解法 -> 迭代的动态规划解法https://github.com/labuladong/fucking-algorithm/tree/master/动态规划系列。但是我硬是想不出来暴力解法。该题两个字符串同时作为变量,用一维的暴力法遍历好像不能够解决(如果有小伙伴可以解决的话,请告诉我一下,我想和你探讨一下)。
  • 二维数组的动态规划算法在控制两个变量上很清晰,斜上方,左方,上方均为上一次的状态。动态规划就好像二维的平面直角坐标系
  • 好好体会将问题分解成子问题,并对子问题的解进行剪枝,抛弃一些无用的解,存放到二维的dp数组中,要明确本题中二维数组的定义是什么。

1143.最长公共子序列相关推荐

  1. leetcode(力扣) 718. 最长重复子数组 1143. 最长公共子序列 1035. 不相交的线 (动态规划)

    文章目录 718. 最长重复子数组 题目描述 思路分析 完整代码 1143. 最长公共子序列 1035. 不相交的线: 这三道题思路基本一样,尤其是最后两道,代码都一样,一点不需要改的,所以放一起把. ...

  2. LeetCode——1143. 最长公共子序列(Longest Common Subsequence)[中等]——分析及代码(Java)

    LeetCode--1143. 最长公共子序列[Longest Common Subsequence][中等]--分析及代码[Java] 一.题目 二.分析及代码 1. 动态规划 (1)思路 (2)代 ...

  3. leetcode 1143. 最长公共子序列

    难度:中等 频次:64 **题目:**给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度.如果不存在 公共子序列 ,返回 0 . 一个字符串的 子序列 是指这样一个 ...

  4. 116. Leetcode 1143. 最长公共子序列 (动态规划-子序列问题)

    步骤一.确定状态: 确定dp数组及下标含义 dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长 公共子序列为dp[i][j] 步骤二.推 ...

  5. 文巾解题1143. 最长公共子序列

    1 题目描述 2 解题思路 我们可以用动态规划解决这个问题. 假设我们用坐标i表示当前遍历到的text1的坐标,j表示当前遍历到的text2的坐标.ret[i][j]表示text1遍历到i,text2 ...

  6. leetcode 1143. 最长公共子序列(dp)

    给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度.如果不存在 公共子序列 ,返回 0 . 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符 ...

  7. LeetCode 1143. 最长公共子序列(动态规划)

    1. 题目 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度. 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符 ...

  8. leetcode - 1143. 最长公共子序列

    给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列. 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何 ...

  9. 【动态规划】LeetCode 1143最长公共子序列

    题目链接:力扣 思路: 动态规划: dp[i][j]表示text1[0:i) 和 text2[0:j)的最长公共子序列的长度 上述表示中,text1[0:i)的长度为i的前缀,text2[0:j)表示 ...

最新文章

  1. 二元函数求最小值 c语言,用C语言实现简单的多元线性回归算法(二)
  2. Java进阶:default方法说明
  3. QT的QCullFace类的使用
  4. html5手机端设置date,H5 input[type='date'] 优化 pc端和移动端的使用
  5. knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案
  6. iframe里面的元素触发父窗口元素事件的jquery代码 转
  7. 蚂蚁金服一面二面试题及答案,职位Java高级工程师
  8. 报错:Unchecked runtime.lastError:Could not establish connection. Receiving end does not exist.
  9. Android:登录保存回显用户信息或配置文件(sharedpreferences)
  10. 提升内外网文件交换安全性,这里有5点建议
  11. grub2 引导光盘
  12. Windows系统Ionic安装教程/Ionic环境配置
  13. 存储过程中SELECT INTO的使用
  14. 爽爆!阿里腾讯都在传的MySQL精华手册,GitHub标星89K
  15. shellcode免杀
  16. qqxml图片代码_动态图的QQXML代码示例——篮球规范动作示范!
  17. TEXMACS在ubuntu下的使用
  18. java抛硬币,抛硬币模拟(Coin Tossing Simulation)
  19. MyOwnFreeHost免费分销空间定制模板管理用户WHMCS整合和空间运营
  20. 第十届全球云计算大会 | 华云数据荣获“2013-2022十周年特别贡献奖”

热门文章

  1. Python接口开发实现步骤详解
  2. strtol()函数与strtoul()函数的用法
  3. Linux环境配置编译orange,orangepi zero2编译环境搭建及传感器测试
  4. Nacos2.2.1安装遇见的坑
  5. NVIDIA rtx3070显卡驱动、算力和cuda版本匹配关系
  6. Redis C客户端API
  7. 华工计算机研究生课程表,华南理工大学2018--2019学年度第一学期硕士研究生课程安排.doc...
  8. html行内元素水平居中显示,CSS实现元素水平居中
  9. 桌面倒计时html,javascript实现下班倒计时效果的方法(可桌面通知)_javascript技巧
  10. ACL2019最佳论文奖出炉,华人包揽众多奖项