Needleman-Wunsch 的维基百科伪代码中的路径是否为 1 索引?

如何解决Needleman-Wunsch 的维基百科伪代码中的路径是否为 1 索引?

https://en.wikipedia.org/wiki/Needleman%E2%80%93Wunsch_algorithm 中的伪代码显示

for i = 1 to length(A)
    for j = 1 to length(B)
    {
        Match ← F(i−1,j−1) + S(Ai,Bj)
        Delete ← F(i−1,j) + d
        Insert ← F(i,j−1) + d
        F(i,j) ← max(Match,Insert,Delete)
    }

对于路径 AB,评分矩阵 F 将具有 A.length+1 行和 B.length+1 列。 i,j 指的是得分矩阵中的位置。但是,在相似度函数中,它使用路径的 ij 索引。对于这个循环,永远不会访问路径的第一个元素。路径不是 0 索引的吗?

解决方法

是的,序列 AB 是 1-indexed 并且 to length(A) 应该读作 <= length(A)

这在动态编程伪代码中很常见,例如维基百科上给出的Longest Common Subsequence伪代码是:

function LCSLength(X[1..m],Y[1..n])
    C = array(0..m,0..n)
    for i := 0..m
        C[i,0] = 0
    for j := 0..n
        C[0,j] = 0
    for i := 1..m
        for j := 1..n
            if X[i] = Y[j]
                C[i,j] := C[i-1,j-1] + 1
            else
                C[i,j] := max(C[i,j-1],C[i-1,j])
    return C[m,n]

(其中 .. 包含在 Ruby 中)

这是为了方便 -- 如果序列是 0 索引的,则有两个典型的更改会使代码更加冗长:

  • 所有序列访问索引从 Sequence[i][j] 变为 Sequence[i-1][j-1]
  • 如果端点不包含在您的语言中,则所有运行 length(Sequence) 的循环都应运行 length(Sequence) + 1。这是必要的,因为查找表的大小为 length(Sequence) + 1

...或者,用您的 0 索引语言填充序列以使其成为 1 索引,然后在不进行上述调整的情况下应用该算法(这可能令人困惑且效率低下,但可能)。

然后,维基百科根据上述 2 条规则将上述代码翻译成 C#(一种 0 索引语言):

static int[,] LcsLength(string a,string b)
{
    int[,] C = new int[a.Length + 1,b.Length + 1]; // (a,b).Length + 1
    for (int i = 0; i < a.Length; i++)
        C[i,0] = 0;
    for (int j = 0; j < b.Length; j++)
        C[0,j] = 0;
    for (int i = 1; i <= a.Length; i++)
        for (int j = 1; j <= b.Length; j++)
        {
            if (a[i - 1] == b[j - 1])//i-1,j-1
                C[i,j] = C[i - 1,j - 1] + 1;
            else
                C[i,j] = Math.Max(C[i,j - 1],C[i - 1,j]);
        }
    return C;
}

我将使用相同的规则将 Needleman-Wunsch 的维基百科伪代码翻译成 Python。

我从 here 获取了一些测试用例,但认为除此之外还未经测试。

此外,正如您在链接的要点中所见,将新元素附加到列表并反转它们比如下所示预先添加字符串更有效,但我选择了维基百科的逐字翻译。

def needleman_wunsch_make_F(A,B,S,d):
    F = [[0] * (len(B) + 1) for _ in range(len(A) + 1)]

    for i in range(0,len(A) + 1):
        F[i][0] = d * i

    for j in range(0,len(B) + 1):
        F[0][j] = d * j

    for i in range(1,len(A) + 1):
        for j in range(1,len(B) + 1):
            match = F[i-1][j-1] + S(A[i-1],B[j-1])
            delete = F[i-1][j] + d
            insert = F[i][j-1] + d
            F[i][j] = max(match,insert,delete)

    return F

def needleman_wunsch_align(A,F,d):
    AlignmentA = "" # TODO use lists for efficiency
    AlignmentB = ""
    i = len(F) - 1
    j = len(F[0]) - 1

    while i > 0 or j > 0:
        if i > 0 and j > 0 and F[i][j] == F[i-1][j-1] + S(A[i-1],B[j-1]):
            AlignmentA = A[i-1] + AlignmentA
            AlignmentB = B[j-1] + AlignmentB
            i -= 1
            j -= 1
        elif i > 0 and F[i][j] == F[i-1][j] + d:
            AlignmentA = A[i-1] + AlignmentA
            AlignmentB = "-" + AlignmentB
            i -= 1
        else:
            AlignmentA = "-" + AlignmentA
            AlignmentB = B[j-1] + AlignmentB
            j -= 1

    return AlignmentA,AlignmentB
    
def needleman_wunsch(A,S=lambda a,b: 1 if a == b else -1,d=-1):
    F = needleman_wunsch_make_F(A,d)
    return needleman_wunsch_align(A,d)

if __name__ == "__main__":
    import collections

    Test = collections.namedtuple("Test","A B exp_A exp_B d")
    tests = (
        Test(A="GATTACA",B="GCATGCU",exp_A="G-ATTACA",exp_B="GCA-TGCU",d=-1),Test(
            A="GCAGGCAAGTGGGGCACCCGTATCCTTTCCAACTTACAAGGGTCCCCGTT",B="GTGCGCCAGAGGAAGTCACTTTATATCCGCGCACGGTACTCCTTTTTCTA",exp_A="----G-C--AGGCAAGTGGGGCACCCGTATCCT-T-T-C-C-AACTTACAAGGGT-C-CC-----CGT-T",exp_B="GTGCGCCAGAGG-AAGT----CA--C-T-T--TATATCCGCG--C--AC---GGTACTCCTTTTTC-TA-",d=0
        ),exp_A="GCAG-GCAAGTGG--GGCAC-CCGTATCCTTTC-CAAC-TTACAAGGGTCC-CCGT-T-",exp_B="G-TGCGCCAGAGGAAGTCACTTTATATCC--GCGC-ACGGTAC-----TCCTTTTTCTA",d=-1
        ),exp_A="GCAGGCAAGTGG--GGCAC-CCGTATCCTTTCCAACTTACAAGGGTCCCCGTT",exp_B="GTGCGCCAGAGGAAGTCACTTTATATCC-GCGCACGGTAC-TCCTTTTTC-TA",d=-2
        ),)

    for A,exp_A,exp_B,d in tests:
        act_A,act_B = needleman_wunsch(A,d=d)
        assert act_A == exp_A
        assert act_B == exp_B

顺便说一句,我编写了一个小应用程序,它将用于将 DP 算法编写为 1 索引的伪代码语言转换为 0 索引的 Python。如果您好奇,它在 GitHub 上。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?