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)的更多相关文章

  1. 子序列 sub sequence问题,例:最长公共子序列,[LeetCode] Distinct Subsequences(求子序列个数)

    引言 子序列和子字符串或者连续子集的不同之处在于,子序列不需要是原序列上连续的值. 对于子序列的题目,大多数需要用到DP的思想,因此,状态转移是关键. 这里摘录两个常见子序列问题及其解法. 例题1, ...

  2. 区间DP+next求循环节 uva 6876

    // 区间DP+next求循环节 uva 6876 // 题意:化简字符串 并表示出来 // 思路:dp[i][j]表示 i到j的最小长度 // 分成两部分 再求一个循环节 #include < ...

  3. HDU 1087 简单dp,求递增子序列使和最大

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  4. 【dp】求最长上升子序列

    题目描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.我们想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要将1到N插入序列中 ...

  5. [LeetCode]152. 乘积最大子序列(DP)

    题目 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数). 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6. 示 ...

  6. 【dp】求最长公共子序列

    [题目描述] 一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X=<x1,x2,…,xm>X=<x1,x2,…,xm>,则另一序列Z=<z1 ...

  7. LeetCode——数组篇:659. 分割数组为连续子序列

    659. 分割数组为连续子序列 输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数.返回你是否能做出这样的分割? 示例 1: 输入: [ ...

  8. Monkey and Banana(dp,求最长的下降子序列)

    A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a bana ...

  9. [LeetCode] Wiggle Subsequence 摆动子序列

    A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...

  10. HDU-3944 DP?(组合数求模)

    一.题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3944 二.题意 给一个巨大的杨辉三角,采用类似DP入门题“数字三角形”的方式求从顶点$(0, 0) ...

随机推荐

  1. android开发阶段性技能

    一.初级 1. 拥有娴熟的Java基础,理解设计模式,比如OOP语言的工厂模式要懂得. 2. 掌握Android UI控件.Android Java层API相关使用. 迈向中级,最好再次更新下Java ...

  2. SpringBoot整合XXLJob

    目录 XXLJob简介 特性 模块 安装调度中心 初始化数据库 配置 启动 整合执行器 pom yml XxlJobConfig 启动执行器 实践 简单的定时任务 在执行器创建任务 在调度中心创建执行 ...

  3. C#桶排序算法

    前言 桶排序是一种线性时间复杂度的排序算法,它将待排序的数据分到有限数量的桶中,每个桶再进行单独排序,最后将所有桶中的数据按顺序依次取出,即可得到排序结果. 实现原理 首先根据待排序数据,确定需要的桶 ...

  4. db-cdc之mysql 深入了解并使用binlog

    1.什么是binlog? 2.binlog可以用来干什么? 3.怎么样使用binlog? binlog是记录所有数据库表结构变更(例如CREATE.ALTER TABLE-)以及表数据修改(INSER ...

  5. 2D物理引擎 Box2D for javascript Games 第五章 碰撞处理

    2D物理引擎 Box2D for javascript Games 第五章 碰撞处理 碰撞处理 考虑到 Box2D 世界和在世界中移动的刚体之间迟早会发生碰撞. 而物理游戏的大多数功能则依赖于碰撞.在 ...

  6. CentOS7 Ceph分布式集群部署

    CentOS 7 下安装Ceph-nautilus 本问主要记录在CentOS 7下如何安装Ceph-nautilus,安装过程中遇到的一些问题及解决方法. 1.Ceph实验准备 以下是本次实验所用到 ...

  7. RLChina2022公开课-博弈搜索算法

    序列决策 序列决策问题一般用马尔可夫决策模型进行描述 搜索算法的优化

  8. Gson替换掉多漏洞的FastJson

    添加依赖: <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> < ...

  9. HarmonyOS UI 开发

    引言 HarmonyOS 提供了强大的 UI 开发工具和组件,使开发者能够创建吸引人的用户界面.本章将详细介绍在 HarmonyOS 中应用 JS.CSS.HTML,HarmonyOS 的 UI 组件 ...

  10. c#利用反射获取枚举的信息

    1.将不同的枚举类型作为形参传入某函数内时,形参为Enum,在函数体内进行类型强转. private T GetEnumType<T>(object o) { T enumVal = (T ...