leecode更新

This commit is contained in:
markilue 2023-02-24 13:43:34 +08:00
parent 108863a5a8
commit 1f674b6b56
3 changed files with 244 additions and 0 deletions

View File

@ -1,5 +1,7 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
@ -15,7 +17,78 @@ package com.markilue.leecode.dynamic.second;
*/
public class T34_NumDistinct {
@Test
public void test(){
String s = "rabbbit", t = "rabbit";
// String s = "babgbag", t = "bag";
System.out.println(numDistinct1(s,t));
}
/**
* 思路:本质上实际上是从是不是子序列变为了 有多少个子序列的问题
* TODO 不同的子序列:
* 1.dp定义: dp[i][j]表示使用s[0-i]能凑出多少个t[0-j]
* 2.dp状态转移方程:
* dp[i][j]的状态分为两种 :
* if s[i]==t[j] 原本能继续凑出 dp[i][j]=dp[i-1][j-1]+dp[i-1][j]
* else 不能继续凑出 dp[i][j]=dp[i-1][j]
* 3.dp初始化:
* 4.dp遍历顺序:
* 5.dp举例推导:以s = "rabbbit", t = "rabbit"为例
* [0 r a b b i t]
* 0: 1 0 0 0 0 0 0
* r: 1 1 0 0 0 0 0
* a: 1 1 1 0 0 0 0
* b: 1 1 1 1 0 0 0
* b: 1 1 1 2 1 0 0
* b: 1 1 1 3 3 0 0
* i: 1 1 1 3 3 3 0
* t: 1 1 1 3 3 3 3
* 速度击败26.62% 内存击败32.5% 16ms
* @param s
* @param t
* @return
*/
public int numDistinct(String s, String t) {
int[][] dp = new int[s.length() + 1][t.length() + 1];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = 1;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
//证明之前匹配上过那么在之前匹配上的基础上+后来匹配上的次数一部分是用s[i - 1]来匹配一部分是不用s[i - 1]来匹配
if (s.charAt(i - 1) == t.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
else dp[i][j] = dp[i - 1][j];
}
}
return dp[s.length()][t.length()];
}
/**
* 一维dp优化
* 速度击败73.25% 内存击败99.63% 11ms
* @param s
* @param t
* @return
*/
public int numDistinct1(String s, String t) {
int[] dp = new int[t.length() + 1];
dp[0] = 1;
for (int i = 1; i < s.length()+1; i++) {
for (int j = t.length(); j >0; j--) {//因为要使用之前的j-1所以就反向遍历
if (s.charAt(i - 1) == t.charAt(j - 1)) dp[j] += dp[j - 1];
}
}
return dp[t.length()];
}
}

View File

@ -0,0 +1,75 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-24 10:32
*@Description:
* TODO 力扣583题 两个字符串的删除操作:
* 给定两个单词 word1 word2 返回使得 word1 word2 相同所需的最小步数
* 每步 可以删除任意一个字符串中的一个字符
*@Version: 1.0
*/
public class T35_MinDistance {
@Test
public void test(){
String word1 = "leetcode", word2 = "etco";
System.out.println(minDistance(word1,word2));
}
/**
* 思路: 每个字符串都能删
* TODO DP五部曲:
* 1.dp定义:dp[i][j]表示使用word1[i]变为word2[j]需要删除的数量
* 2.dp状态转移方程:
* 1.当word1[i]==word2[j] 则不需要多加操作
* dp[i][j]=dp[i-1][j-1]
* 2.当word1[i]!=word2[j] 则需要在之前多加操作
* dp[i][j]= min(dp[i-1][j]+1,dp[i][j-1]+1)
* 3.dp初始化: dp[i][0]=i dp[0][j]=j
* 4.dp遍历顺序:
* 5.dp举例推导:以word1 = "leetcode", word2 = "etco"为例
* [0 e t c o]
* 0 0 1 2 3 4
* l 1 2 3 4 5
* e 2 1 2 3 4
* e 3
* t 4
* c 5
* o 6
* d 7
* e 8
* 速度击败62.53% 内存击败39.37% 7ms
* @param word1
* @param word2
* @return
*/
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = i;
}
for (int i = 0; i < dp[0].length; i++) {
dp[0][i] = i;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1];
else dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
}
}
return dp[word1.length()][word2.length()];
}
}

View File

@ -0,0 +1,96 @@
package com.markilue.leecode.dynamic.second;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic.second
*@Author: markilue
*@CreateTime: 2023-02-24 11:09
*@Description:
* TODO 力扣72题 编辑距离:
* 给你两个单词 word1 word2 请返回将 word1 转换成 word2 所使用的最少操作数
* 你可以对一个单词进行如下三种操作
* 插入一个字符
* 删除一个字符
* 替换一个字符
*@Version: 1.0
*/
public class T36_MinDistance {
@Test
public void test(){
String word1 = "horse", word2 = "ros";
System.out.println(minDistance(word1,word2));
}
/**
* 思路:更复杂的地方在于 编辑存在三种操作: 应该如何处理
* TODO dp五部曲:
* 1.dp定义:dp[i][j]表示word1[0-i]通过三种操作最少能花多少步变成word2[0-j]
* 2.dp状态转移方程:
* 1.当word1[i]!=word1[j] 删除 修改 插入
* dp[i][j]=min(dp[i-1][j]+1,dp[i-1][j-1]+1dp[i][j-1]+1)
* else dp[i][j]=dp[i-1][j-1]
* 3.dp初始化:
* 4.dp遍历顺序:
* 5.dp举例推导:
* 速度击败45.95% 内存击败14.7% 5ms
* @param word1
* @param word2
* @return
*/
public int minDistance(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
for (int i = 0; i < dp.length; i++) {
dp[i][0]=i;
}
for (int i = 0; i < dp[0].length; i++) {
dp[0][i]=i;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if(word1.charAt(i-1)==word2.charAt(j-1)) dp[i][j]=dp[i-1][j-1];
else dp[i][j]=Math.min(Math.min(dp[i-1][j]+1,dp[i-1][j-1]+1),dp[i][j-1]+1);
}
}
return dp[word1.length()][word2.length()];
}
/**
* toCharArray()优化
* 速度击败95.84% 内存击败60.85%
* @param word1
* @param word2
* @return
*/
public int minDistance1(String word1, String word2) {
int[][] dp = new int[word1.length() + 1][word2.length() + 1];
char[] char1 = word1.toCharArray();
char[] char2 = word2.toCharArray();
for (int i = 0; i < dp.length; i++) {
dp[i][0]=i;
}
for (int i = 0; i < dp[0].length; i++) {
dp[0][i]=i;
}
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if(char1[i-1]==char2[j-1]) dp[i][j]=dp[i-1][j-1];
else dp[i][j]=Math.min(Math.min(dp[i-1][j]+1,dp[i-1][j-1]+1),dp[i][j-1]+1);
}
}
return dp[word1.length()][word2.length()];
}
}