刷题漫漫路(四)| 豆包MarsCode AI刷题

33 阅读4分钟

在解决字符串比较与编辑距离的问题时,使用动态规划是一种有效的手段。以下是我对你提供的 DNA 序列比对(编辑距离)代码的详细分析与理解,包括实现过程、核心逻辑、潜在的优化和总结。

问题分析

编辑距离是计算两个字符串之间相同的最小操作数,这些操作包括插入、删除和替换。对于 DNA 序列,这个问题可以用动态规划进行求解,具体步骤如下:

  1. 定义状态:使用一个二维数组 dp 来存储 DNA 序列 dna1 和 dna2 在前 i 和前 j 个字符上的编辑距离。dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最小操作数。

  2. 初始化

    • dp[i][0] 表示 dna1 的前 i 个字符转换为一个空字符串的操作数,等于 i(即删除所有字符)。
    • dp[0][j] 表示空字符串转换为 dna2 的前 j 个字符的操作数,等于 j(即需要插入 j 个字符)。
  3. 状态转移:对于每对字符:

    • 如果字符相同,则 dp[i][j] 等于 dp[i-1][j-1](不需要任何操作)。

    • 如果字符不同,则取三种操作中所需的最小操作,然后加一:

      • 插入:dp[i][j-1] + 1
      • 删除:dp[i-1][j] + 1
      • 替换:dp[i-1][j-1] + 1
  4. 结果:最终返回 dp[m][n],即将 dna1 完全匹配到 dna2 所需的最小编辑距离。

以下是代码实现:

python
def solution(dna1, dna2):  
    m, n = len(dna1), len(dna2)  
    dp = [[0] * (n + 1) for _ in range(m + 1)]  

    # 初始化 dp 数组  
    for i in range(m + 1):  
        dp[i][0] = i  # 需要 i 次删除  
    for j in range(n + 1):  
        dp[0][j] = j  # 需要 j 次插入  

    # 填充 dp 数组  
    for i in range(1, m + 1):  
        for j in range(1, n + 1):  
            if dna1[i - 1] == dna2[j - 1]:  
                dp[i][j] = dp[i - 1][j - 1]  
            else:  
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1  

    # 返回最终结果  
    return dp[m][n]  


if __name__ == "__main__":  
    # 你可以在这里添加更多的测试用例  
    print(solution("AGCTTAGC", "AGCTAGCT") == 2)  # 期望输出 2  
    print(solution("AGCCGAGC", "GCTAGCT") == 4)   # 期望输出 4  

代码解析

  1. 动态数组初始化

    • dp[i][0] 和 dp[0][j] 的设置为正确的边界条件,这是动态规划的基础。
  2. 双重循环填充数组

    • 外层循环是对 dna1 的每一个字符,内层循环是对 dna2 的每一个字符,确保每对字符的编辑距离被正确计算。
  3. 状态转移的简洁性

    • 使用 if 语句来判断字符是否相同,这样能简洁地处理编辑操作。

心得体会

  1. 动态规划的设计:动态规划是一种有效处理问题的方法,理解问题的状态和转移关系是成功应用此算法的关键。通过定义状态并清晰地管理状态转移,可以有效地优化复杂度。
  2. 充分初始化:在这个问题中,正确初始化 dp 数组非常重要。如果不准确,后续的计算将出现错误,导致不正确的结果。
  3. 测试用例的多样性:在测试过程中,应考虑不同场景,例如完全相同的序列、完全不同的序列,以及包含空字符串的情况。每种情况都可以帮助验证算法的正确性和鲁棒性。
  4. 炼化返回值:在本代码中,return -2 这一行实际上是多余的,可以安全删除。良好的代码应该避免不必要的返回语句,以减少混淆和错误。

代码的优化

尽管目前的实现已经有效,但我们可以考虑以下优化:

  • 空间优化:当前实现的时间复杂度和空间复杂度都是 O(m*n)。可以通过使用一维数组来优化空间复杂度,从而节约内存,特别是在处理更长的序列时。
  • 编辑操作的记录:可以扩展该实现来不仅返回最小编辑距离,还返回具体的编辑操作(插入、删除、替换),这将大大增强算法的应用范围。

总结

通过这次的代码实现与分析,我更好地理解了编辑距离算法的原理及其实现方式。这样的编码练习不仅提高了我对动态规划的掌握,还能让我在解决其他复杂字符串处理问题时更加自信。未来,我将继续探索更高效的算法与数据结构,以及如何将复杂问题转化为可解的子问题。