青训营X豆包MarsCode AI刷题妙用 | 豆包MarsCode AI刷题

32 阅读6分钟

这些天不是正想去找一些比较有意思的部分进行刷题训练,毕竟每天刷题的苦逼日子是真的难搞。

这刚好青训营就来了,我就找了几个比较有意思的题目 这个题目呢

类似于力扣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 <= 500
  • word1word2 由小写英文字母组成

代码如下

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. 程序的结构

代码分为以下几个部分:

  1. solution(String dna1, String dna2)
    解决 DNA 序列间的最小编辑距离问题
  2. minDistance(String word1, String word2)
    使用动态规划算法计算两个字符串的最小编辑距离
  3. minMoves(int[] nums, int k)
    解决将二进制数组中 k1 聚集在一起所需的最小移动次数问题。
  4. main 方法
    用于测试 solution 方法。

2. 方法的具体功能

(a) 方法:solution(String dna1, String dna2)

  • 作用:计算 DNA 序列 dna1dna2 之间的最小编辑距离。

  • 实现步骤

    1. 创建 Main 类的实例。
    2. 调用 minDistance 方法,传入两个 DNA 序列。
    3. 返回 minDistance 的结果。

(b) 方法:minDistance(String word1, String word2)

  • 作用:实现计算字符串间最小编辑距离的动态规划算法
  • 算法原理:通过动态规划填充一个二维数组 dp,其中 dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最小操作数。

具体步骤

  1. 初始化:

    • word1 长度为 mword2 长度为 n,则创建一个大小为 (m+1) x (n+1) 的二维数组 dp

    • 基础情况:

      • dp[i][0] = i(从 word1 转为空字符串,需要删除 i 个字符)。
      • dp[0][j] = j(从空字符串转为 word2,需要插入 j 个字符)。
  2. 填充 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;
        
  3. 返回结果:dp[m][n] 表示将 word1 转换为 word2 所需的最小操作数。


(c) 方法:minMoves(int[] nums, int k)

  • 作用:计算将二进制数组 numsk1 聚集在一起所需的最小移动次数。

  • 算法思路

    1. 预处理

      • nums 转化为一个存储所有 1 的位置的数组 p,并调整索引使其归一化。
      • 若数组全为 1,直接返回 0
    2. 滑动窗口

      • 使用窗口大小为 k 计算移动成本:

        • sl:窗口左侧的总成本。
        • sm:窗口中心的总成本。
        • sr:窗口右侧的总成本。
      • 每次滑动窗口时,更新左、中、右成本,计算当前窗口的移动次数,并更新最小值。

    3. 返回结果:ans 表示将 k1 聚在一起所需的最小移动次数。


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
  • 总操作次数:4


复杂度分析

  1. minDistance 方法

    • 时间复杂度:O(m⋅n)O(m⋅n),其中 mm 和 nn 分别为两个字符串的长度。
    • 空间复杂度:O(m⋅n)O(m⋅n),用于存储 dp 数组。
  2. minMoves 方法

    • 时间复杂度:O(n+k)O(n+k),其中 nn 为数组长度,kk 为窗口大小。
    • 空间复杂度:O(m)O(m),其中 mm 是数组中 1 的数量。

总结

  • 该代码采用动态规划和滑动窗口技术,解决了字符串编辑距离和二进制数组最小移动问题。
  • 模块化的设计使得代码清晰易维护,并且能够方便扩展和测试。

很多时候我们不要仅仅去靠人工去审读代码,我们要借助新质生产力去帮助我们达到目的 AI豆包在这一块还是不错的

然后还有一个功能比较不错 也就是自动分类有些时候我准备进行专项训练的时候会选择AI刷题模式,例如我要训练栈我就直接找栈就可以练会这一个知识点了