1143.最长公共子序列
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.最长公共子序列相关推荐
- leetcode(力扣) 718. 最长重复子数组 1143. 最长公共子序列 1035. 不相交的线 (动态规划)
文章目录 718. 最长重复子数组 题目描述 思路分析 完整代码 1143. 最长公共子序列 1035. 不相交的线: 这三道题思路基本一样,尤其是最后两道,代码都一样,一点不需要改的,所以放一起把. ...
- LeetCode——1143. 最长公共子序列(Longest Common Subsequence)[中等]——分析及代码(Java)
LeetCode--1143. 最长公共子序列[Longest Common Subsequence][中等]--分析及代码[Java] 一.题目 二.分析及代码 1. 动态规划 (1)思路 (2)代 ...
- leetcode 1143. 最长公共子序列
难度:中等 频次:64 **题目:**给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度.如果不存在 公共子序列 ,返回 0 . 一个字符串的 子序列 是指这样一个 ...
- 116. Leetcode 1143. 最长公共子序列 (动态规划-子序列问题)
步骤一.确定状态: 确定dp数组及下标含义 dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长 公共子序列为dp[i][j] 步骤二.推 ...
- 文巾解题1143. 最长公共子序列
1 题目描述 2 解题思路 我们可以用动态规划解决这个问题. 假设我们用坐标i表示当前遍历到的text1的坐标,j表示当前遍历到的text2的坐标.ret[i][j]表示text1遍历到i,text2 ...
- leetcode 1143. 最长公共子序列(dp)
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度.如果不存在 公共子序列 ,返回 0 . 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符 ...
- LeetCode 1143. 最长公共子序列(动态规划)
1. 题目 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度. 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符 ...
- leetcode - 1143. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列. 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何 ...
- 【动态规划】LeetCode 1143最长公共子序列
题目链接:力扣 思路: 动态规划: dp[i][j]表示text1[0:i) 和 text2[0:j)的最长公共子序列的长度 上述表示中,text1[0:i)的长度为i的前缀,text2[0:j)表示 ...
最新文章
- 二元函数求最小值 c语言,用C语言实现简单的多元线性回归算法(二)
- Java进阶:default方法说明
- QT的QCullFace类的使用
- html5手机端设置date,H5 input[type='date'] 优化 pc端和移动端的使用
- knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案
- iframe里面的元素触发父窗口元素事件的jquery代码 转
- 蚂蚁金服一面二面试题及答案,职位Java高级工程师
- 报错:Unchecked runtime.lastError:Could not establish connection. Receiving end does not exist.
- Android:登录保存回显用户信息或配置文件(sharedpreferences)
- 提升内外网文件交换安全性,这里有5点建议
- grub2 引导光盘
- Windows系统Ionic安装教程/Ionic环境配置
- 存储过程中SELECT INTO的使用
- 爽爆!阿里腾讯都在传的MySQL精华手册,GitHub标星89K
- shellcode免杀
- qqxml图片代码_动态图的QQXML代码示例——篮球规范动作示范!
- TEXMACS在ubuntu下的使用
- java抛硬币,抛硬币模拟(Coin Tossing Simulation)
- MyOwnFreeHost免费分销空间定制模板管理用户WHMCS整合和空间运营
- 第十届全球云计算大会 | 华云数据荣获“2013-2022十周年特别贡献奖”
热门文章
- Python接口开发实现步骤详解
- strtol()函数与strtoul()函数的用法
- Linux环境配置编译orange,orangepi zero2编译环境搭建及传感器测试
- Nacos2.2.1安装遇见的坑
- NVIDIA rtx3070显卡驱动、算力和cuda版本匹配关系
- Redis C客户端API
- 华工计算机研究生课程表,华南理工大学2018--2019学年度第一学期硕士研究生课程安排.doc...
- html行内元素水平居中显示,CSS实现元素水平居中
- 桌面倒计时html,javascript实现下班倒计时效果的方法(可桌面通知)_javascript技巧
- ACL2019最佳论文奖出炉,华人包揽众多奖项