这些天不是正想去找一些比较有意思的部分进行刷题训练,毕竟每天刷题的苦逼日子是真的难搞。
这刚好青训营就来了,我就找了几个比较有意思的题目 这个题目呢
类似于力扣72编辑距离,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')
提示:
0 <= word1.length, word2.length <= 500word1和word2由小写英文字母组成
代码如下
public class Main {
public static int solution(String dna1, String dna2) {
// Please write your code here
Main main = new Main();
int res = main.minDistance(dna1, dna2);
return res;
}
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化
for (int i = 1; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 因为dp数组有效位从1开始
// 所以当前遍历到的字符串的位置为i-1 | j-1
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][j - 1]), dp[i - 1][j]) + 1;
}
}
}
return dp[m][n];
}
public int minMoves(int[] nums, int k) {
int n = nums.length, m = 0;
for (int i = 0; i < n; ++i)
if (nums[i] != 0) {
nums[m] = i - m;
++m;
}
if (m == n) return 0; // 全部都是 1
int[] p = nums;
int sl = 0, sm = 0, sr = 0; // s[i] s[i+k/2] s[i+k]
for (int i = 0; i < k; ++i) {
if (i < k / 2) sm += p[i];
sr += p[i];
}
int ans = Integer.MAX_VALUE;
for (int i = 0; i <= m - k; ++i) {
ans = Math.min(ans, sl + sr - sm * 2 - p[i + k / 2] * (k % 2));
sl += p[i];
sm += p[i + k / 2];
sr += p[i + k];
}
return ans;
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("AGCTTAGC", "AGCTAGCT") == 2);
System.out.println(solution("AGCCGAGC", "GCTAGCT") == 4);
}
}
这两个题目其实名字都是快类似的 DNA序列编辑距离
看不懂文章怎么办,我们可以快速的去问豆包嘛 ChatGPT
好的!以下是对代码的详细中文解析:
1. 程序的结构
代码分为以下几个部分:
solution(String dna1, String dna2)
解决 DNA 序列间的最小编辑距离问题。minDistance(String word1, String word2)
使用动态规划算法计算两个字符串的最小编辑距离。minMoves(int[] nums, int k)
解决将二进制数组中k个1聚集在一起所需的最小移动次数问题。main方法
用于测试solution方法。
2. 方法的具体功能
(a) 方法:solution(String dna1, String dna2)
-
作用:计算 DNA 序列
dna1和dna2之间的最小编辑距离。 -
实现步骤:
- 创建
Main类的实例。 - 调用
minDistance方法,传入两个 DNA 序列。 - 返回
minDistance的结果。
- 创建
(b) 方法:minDistance(String word1, String word2)
- 作用:实现计算字符串间最小编辑距离的动态规划算法。
- 算法原理:通过动态规划填充一个二维数组
dp,其中dp[i][j]表示将word1的前i个字符转换为word2的前j个字符所需的最小操作数。
具体步骤:
-
初始化:
-
若
word1长度为m,word2长度为n,则创建一个大小为(m+1) x (n+1)的二维数组dp。 -
基础情况:
dp[i][0] = i(从word1转为空字符串,需要删除i个字符)。dp[0][j] = j(从空字符串转为word2,需要插入j个字符)。
-
-
填充
dp数组:-
遍历字符串的每个字符:
-
若当前字符相等,则无需新增操作:
java 复制代码 dp[i][j] = dp[i-1][j-1]; -
若字符不同,取以下三种操作的最小值加 1:
- 替换字符:
dp[i-1][j-1] - 删除字符:
dp[i-1][j] - 插入字符:
dp[i][j-1]
java 复制代码 dp[i][j] = Math.min( Math.min(dp[i-1][j-1], dp[i][j-1]), dp[i-1][j] ) + 1; - 替换字符:
-
-
-
返回结果:
dp[m][n]表示将word1转换为word2所需的最小操作数。
(c) 方法:minMoves(int[] nums, int k)
-
作用:计算将二进制数组
nums中k个1聚集在一起所需的最小移动次数。 -
算法思路:
-
预处理:
- 将
nums转化为一个存储所有1的位置的数组p,并调整索引使其归一化。 - 若数组全为
1,直接返回0。
- 将
-
滑动窗口:
-
使用窗口大小为
k计算移动成本:sl:窗口左侧的总成本。sm:窗口中心的总成本。sr:窗口右侧的总成本。
-
每次滑动窗口时,更新左、中、右成本,计算当前窗口的移动次数,并更新最小值。
-
-
返回结果:
ans表示将k个1聚在一起所需的最小移动次数。
-
3. 主方法:main(String[] args)
-
用于测试
solution方法:-
测试用例 1:
java 复制代码 solution("AGCTTAGC", "AGCTAGCT");输出结果应为
2。 -
测试用例 2:
java 复制代码 solution("AGCCGAGC", "GCTAGCT");输出结果应为
4。
-
4. 示例分析
示例 1
java
复制代码
solution("AGCTTAGC", "AGCTAGCT");
-
输入字符串:
"AGCTTAGC"和"AGCTAGCT"。 -
操作:
- 删除
"AGCT**T**AGC"中第 5 个字符T。 - 在
"AGCTAGC"后插入T。
- 删除
-
总操作次数:
2。
示例 2
java
复制代码
solution("AGCCGAGC", "GCTAGCT");
-
输入字符串:
"AGCCGAGC"和"GCTAGCT"。 -
操作:
- 将第 1 个字符
A替换为G。 - 将第 3 个字符
C替换为T。 - 删除第 7 和第 8 个字符
C。
- 将第 1 个字符
-
总操作次数:
4。
复杂度分析
-
minDistance方法:- 时间复杂度:O(m⋅n)O(m⋅n),其中 mm 和 nn 分别为两个字符串的长度。
- 空间复杂度:O(m⋅n)O(m⋅n),用于存储
dp数组。
-
minMoves方法:- 时间复杂度:O(n+k)O(n+k),其中 nn 为数组长度,kk 为窗口大小。
- 空间复杂度:O(m)O(m),其中 mm 是数组中
1的数量。
总结
- 该代码采用动态规划和滑动窗口技术,解决了字符串编辑距离和二进制数组最小移动问题。
- 模块化的设计使得代码清晰易维护,并且能够方便扩展和测试。
很多时候我们不要仅仅去靠人工去审读代码,我们要借助新质生产力去帮助我们达到目的 AI豆包在这一块还是不错的
然后还有一个功能比较不错 也就是自动分类有些时候我准备进行专项训练的时候会选择AI刷题模式,例如我要训练栈我就直接找栈就可以练会这一个知识点了