DNA序列还原(golang)

44 阅读2分钟

问题描述

给定一段受损的 DNA 碱基序列 dna1,在每次只操作一个碱基的情况下,将其以最少的操作步骤将其还原到未受损的 DNA 碱基序列 dna2。

只可以对 DNA 碱基序列中的一个碱基进行三种操作:

  1. 增加一个碱基
  2. 去除一个碱基
  3. 替换一个碱基

思路

动态规划(Dynamic Programming, DP)。我们定义一个二维数组 dp,其中 dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最小操作数。

  • 初始状态: dp[0][0] = 0,因为将空字符串转换为空字符串不需要任何操作。 dp[i][0] = i,因为将前 i 个字符的 dna1 转换为空字符串需要 i 次删除操作。 dp[0][j] = j,因为将空字符串转换为前 j 个字符的 dna2 需要 j 次插入操作。
  • 状态转移方程: 如果 dna1[i-1] == dna2[j-1],则 dp[i][j] = dp[i-1][j-1],因为最后一个字符相同,不需要额外操作。 如果dna1[i-1] != dna2[j-1] 则需要考虑三种操作:
    • 插入操作:dp[i][j] = dp[i][j-1] + 1
    • 删除操作:dp[i][j] = dp[i-1][j] + 1
    • 替换操作:dp[i][j] = dp[i-1][j-1] + 1

代码

package main

import "fmt"

func solution(dna1, dna2 string) int {
	// Please write your code here
	len1 := len(dna1)
	len2 := len(dna2)
	var dp [][]int = make([][]int, len1+1)
	for i := 0; i < len1+1; i++ {
		dp[i] = make([]int, len2+1)
	}

	for i := 1; i < len1+1; i++ {
		dp[i][0] = i // 因为将前 i 个字符的 dna1 转换为空字符串需要 i 次删除操作
	}

	for j := 1; j < len2+1; j++ {
		dp[0][j] = j // 因为将空字符串转换为前 j 个字符的 dna2 需要 j 次插入操作
	}

	dp[0][0] = 0 // 因为将空字符串转换为空字符串不需要任何操作

	for i := 1; i < len1+1; i++ {
		for j := 1; j < len2+1; j++ {
			if dna1[i-1] == dna2[j-1] {
				dp[i][j] = dp[i-1][j-1] // 如果 dna1[i-1] == dna2[j-1],则 dp[i][j] = dp[i-1][j-1],因为最后一个字符相同,不需要额外操作
			} else {
				dp[i][j] = min(dp[i-1][j]+1 /*删除操作*/, dp[i][j-1]+1/*插入操作*/, dp[i-1][j-1]+1 /*替换操作*/)
			}
		}
	}

	return dp[len1][len2]
}

func main() {
	//  You can add more test cases here
	fmt.Println(solution("AGCTTAGC", "AGCTAGCT") == 2)
	fmt.Println(solution("AGCCGAGC", "GCTAGCT") == 4)
}