LeetCode DP篇-求子序列问题(1143、300、53、72)
1143. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。
若这两个字符串没有公共子序列,则返回 0。
示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace",它的长度为 3。
示例 2:
输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc",它的长度为 3。
示例 3:
输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0。
提示:
1 <= text1.length <= 1000
1 <= text2.length <= 1000
输入的字符串只含有小写英文字符。
思路
//思路1:暴力,找出其中一个string的所有子序列,然后拿去第二个进行匹配,匹配到即为公告子序列
//思路2:动态规划,将两个String当初二维数组的行列,从两个String的第一个字符关系进行比较,逐渐增加字符个数,递推进行
solution1 dp
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m+1][n+1];
for (int i=1; i<m+1; i++){
for (int j=1; j<n+1; j++){
if (text1.charAt(i-1) == text2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1] + 1; //(i,j)=(i-1,j-1),因此从1开始遍历到m+1
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[m][n];
}
}
dp2
//通过将字符串转化为char数组提升性能
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
char[] chars1 = text1.toCharArray();
char[] chars2 = text2.toCharArray();
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m+1][n+1];
for(int i = 1; i < m+1; i++){
for(int j = 1; j < n+1; j++){
if (chars1[i-1] == chars2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[m][n];
}
}
最长公共子串
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
char[] chars1 = text1.toCharArray();
char[] chars2 = text2.toCharArray();
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m+1][n+1];
int max = 0;
for(int i = 1; i < m+1; i++){
for(int j = 1; j < n+1; j++){
if (chars1[i-1] == chars2[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
max = Math.max(max,dp[i][j]);
}
}
}
return max;
}
}
300. 最长上升子序列
给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
solution1 普通动态规划
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp,1);
for (int i = 0; i < nums.length; i++){
for (int j = 0; j < i; j++){
if(nums[j]<nums[i]) dp[i] = Math.max(dp[i],dp[j]+1);
}
}
int res = 0;
for(int i = 0; i < nums.length; i++){
res = Math.max(res,dp[i]);
}
return res;
}
}
//普通dp
//1.dp数组
//2.求base case
//2.数学归纳法求dp[i],即确定状态转移方程
solution2 优化dp
class Solution {
public int lengthOfLIS(int[] nums) {
int[] top = new int[nums.length];
int piles = 0;
for (int i = 0; i < nums.length; i++){
int left = 0, right = piles;
int curr = nums[i];
//二分查找,查找小于当前且最大的数
while(left < right){
int mid = (left + right) >> 1;
if (top[mid] > curr){
right = mid;
}else if(top[mid] < curr){
left = mid + 1;
}else{
right = mid;
}
}
//牌堆最大值小于当前,新建堆
if (left == piles) piles ++;
top[left] = curr;
}
return piles;
}
}
//优化dp
//在普通dp状态方程的求解上,利用二分查找,将时间复杂度缩小到 O(log N)
//参考资料:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-she-ji-fang-fa-zhi-pai-you-xi-jia/
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i = 1; i < nums.length; i++){
dp[i] = Math.max(nums[i],nums[i]+dp[i-1]);
}
int res = Integer.MIN_VALUE;
for(int j = 0; j < nums.length; j++){
res = Math.max(dp[j],res);
}
return res;
}
}
//!!!考虑每一数加不加入之前还是另起数组
//1、dp数组,每一状态保存有当前数加入的最大和子串
//2、dp[0] = nums[0]
//3、状态转移:max(nums[i],nums[i]+dp[i-1])
72. 编辑距离
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
示例 2:
输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
solution1 暴力递归
class Solution {
public int minDistance(String word1, String word2) {
char[] c1 = word1.toCharArray();
char[] c2 = word2.toCharArray();
return helper(c1,c2,c1.length-1,c2.length-1);
}
public int helper(char[] c1, char[] c2, int n, int m){
if (n == -1) return m+1;
if (m == -1) return n+1;
if (c1[n] == c2[m]){
return helper(c1,c2,n-1,m-1); //相同不用改变
}else{ //删除、插入、交换改变最小的那一个
return Math.min(helper(c1,c2,n-1,m)+1,
Math.min(helper(c1,c2,n,m-1)+1,
helper(c1,c2,n-1,m-1)+1)
);
}
}
}
// String st = String.valueOf(c);
// char[] c = st.toCharArray();
//类似最长公共子序列
//思路1:暴力递归 找出每个操作中删除、插入、交换改变最小的那一个
solution2 带备忘录的递归(自顶向下)
class Solution {
public int minDistance(String word1, String word2) {
char[] c1 = word1.toCharArray();
char[] c2 = word2.toCharArray();
int[][] menu = new int[c1.length][c2.length];
return helper(c1,c2,c1.length-1,c2.length-1,menu);
}
public int helper(char[] c1, char[] c2, int n, int m, int[][] menu){
if (n == -1) return m+1;
if (m == -1) return n+1;
if (menu[n][m] != 0) return menu[n][m];
if (c1[n] == c2[m]){
return menu[n][m] = helper(c1,c2,n-1,m-1,menu); //相同不用改变
}else{ //删除、插入、交换改变最小的那一个
return menu[n][m] = Math.min(helper(c1,c2,n-1,m,menu)+1,
Math.min(helper(c1,c2,n,m-1,menu)+1,
helper(c1,c2,n-1,m-1,menu)+1)
);
}
}
}
// String st = String.valueOf(c);
// char[] c = st.toCharArray();
//类似最长公共子序列
//思路1:暴力递归 找出每个操作中删除、插入、交换改变最小的那一个
//思路2:加个备忘录进行记录
solution3 动态规划(自底向上)
class Solution {
public int minDistance(String word1, String word2) {
char[] c1 = word1.toCharArray();
char[] c2 = word2.toCharArray();
int[][] dp = new int[c1.length+1][c2.length+1];
//base case
for (int i = 0; i < c1.length+1; i++) dp[i][0] = i;
for (int j = 0; j < c2.length+1; j++) dp[0][j] = j;
//状态转移
for (int i = 1; i < c1.length+1; i++){
for (int j = 1; j < c2.length+1; j++){
if(c1[i-1] == c2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = Math.min(dp[i-1][j]+1,Math.min(dp[i][j-1]+1,dp[i-1][j-1]+1));
}
}
return dp[c1.length][c2.length];
}
}
// String st = String.valueOf(c);
// char[] c = st.toCharArray();
//类似最长公共子序列
//思路1:暴力递归 找出每个操作中删除、插入、交换改变最小的那一个
//思路2:加个备忘录进行记录
//思路3:1.dp数组 2.base case 3.根据实际情况列动态递归方程
LeetCode DP篇-求子序列问题(1143、300、53、72)的更多相关文章
- 子序列 sub sequence问题,例:最长公共子序列,[LeetCode] Distinct Subsequences(求子序列个数)
引言 子序列和子字符串或者连续子集的不同之处在于,子序列不需要是原序列上连续的值. 对于子序列的题目,大多数需要用到DP的思想,因此,状态转移是关键. 这里摘录两个常见子序列问题及其解法. 例题1, ...
- 区间DP+next求循环节 uva 6876
// 区间DP+next求循环节 uva 6876 // 题意:化简字符串 并表示出来 // 思路:dp[i][j]表示 i到j的最小长度 // 分成两部分 再求一个循环节 #include < ...
- HDU 1087 简单dp,求递增子序列使和最大
Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
- 【dp】求最长上升子序列
题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.我们想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要将1到N插入序列中 ...
- [LeetCode]152. 乘积最大子序列(DP)
题目 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6. 示 ...
- 【dp】求最长公共子序列
[题目描述] 一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X=<x1,x2,…,xm>X=<x1,x2,…,xm>,则另一序列Z=<z1 ...
- LeetCode——数组篇:659. 分割数组为连续子序列
659. 分割数组为连续子序列 输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数.返回你是否能做出这样的分割? 示例 1: 输入: [ ...
- Monkey and Banana(dp,求最长的下降子序列)
A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a bana ...
- [LeetCode] Wiggle Subsequence 摆动子序列
A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...
- HDU-3944 DP?(组合数求模)
一.题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3944 二.题意 给一个巨大的杨辉三角,采用类似DP入门题“数字三角形”的方式求从顶点$(0, 0) ...
随机推荐
- chatgpt 非常不稳定
写一个飞机大战游戏 很抱歉,作为一名语言模型,我没有具体的编程功能,无法直接为您编写一个飞机大战游戏.不过,我可以为您提供一些创建飞机大战游戏的一般步骤和建议. 设计游戏元素 首先,您 ...
- 【RocketMQ】RocketMQ 5.0新特性(三)- Controller模式
在RocketMQ 5.0以前,有两种集群部署模式,分别为主从模式(Master-Slave模式)和Dledger模式. 主从模式 主从模式中分为Master和Slave两个角色,集群中可以有多个Ma ...
- ES6和node模块化
node模块化: 1.输出:exports.a=12; 或者module.exports={ a:12, b:5 } 2.引入:require('./a.js'); 3.引用自定义模块 放到node_ ...
- 牛逼!Github上最有价值的一个开源项目!
哈喽,我是老鱼,一名致力于在技术道路上的终身学习者.实践者.分享者! 今天介绍的这个项目,我愿称之为Github最有价值的开源项目! 一个小而全而美的第三方登录开源组件,相信你一定能用的上~ Just ...
- JavsScript对密码进行Base64加密和Base64解密
const password = "hello"; // 进行Base64加密 let pwd64 = window.btoa(password); console.log(pwd ...
- 中兴GoldenDB(MYSQL)营运商SQL优化案例(超复杂SQL)
陆老师好久没找我,今天他在营运商遇到2条性能慢的SQL,说找了好多专家老手看了都优化不了,然后就找到我打算给我玩玩. 第一次接触营运商行业的SQL,妈呦还真的复杂 SQL1: SELECT WORK ...
- OpenGL 坐标系统详解
GL中的坐标系是标准设备坐标,即他的每个坐标轴的取值范围都是[-1.0,1.0].通常,我们输入到顶点着色器中的顶点坐标都会被转换为标准化设备坐标,然后进行光栅化,转变成屏幕坐标.然而事实上,从顶点坐 ...
- TypeScript学习小结:基础使用
TypeScript学习小结:基础使用 某册子买了两年多了,到最近才开始学习TypeScript,拖延症的严重症状了:不过我还是深信人做一件事是需要一个契机的. 学完之后整体感受是:TypeScrip ...
- [动态树] Link-Cut Tree
Link-Cut Tree 0x00 绪言 学长们讲 LCT 的时候,我在另一个机房摸鱼,所以没有听到,就回家看 yxc 的补了补. 0x01 什么是动态树 动态树问题, 即要求我们维护一个由若干棵子 ...
- Hadoop学习(一) 搭建伪分布式集群
文章结构 1.准备工作 1.1 配置IP 1.2 关闭防火墙 1.3 修改主机名并与IP绑定 1.4 创建新用户 1.5 配置免密匙 2.安装并配置Hadoop伪分布式集群 2.1 安装Java 2. ...