【问题标题】:Java characters alignment algorithmJava字符对齐算法
【发布时间】:2013-02-23 16:41:28
【问题描述】:

我有两个要对齐的 100 个字符的数组(最大值,可以小于或不同的大小)。当字符与另一个字符不同时,我想添加一个“-”。我找到了基于动态编程的Needleman–Wunsch 算法和基于动态编程的通用局部对齐方法Smith–Waterman 算法,但它们对于我想做的事情来说似乎太复杂了。我只需要一个简单的Java算法,大概不到50行,这段代码会被翻译成汇编语言,所以我需要一个简单的算法。

有没有办法用 diff 算法进行这种对齐?如果是的话,有人可以指出我该怎么做吗?我在biostar部分搜索,但似乎我需要使用我提到的两种算法。

英语不是我的母语,所以也许我搜索了错误的关键字。

我的程序已经使用 Needleman 算法及其大约 200 行(ish)代码。

所需输入/输出示例:

Input
Array 1 : MKNLASREVNIYVNGKLV
Array 2 : QMASREVNIYVNGKL


Output
Array 1 (or a simple print) : -MKNLASREVNIYVNGKLV 
Array 2 (or a simple print) : QM---ASREVNIYVNGKL-

【问题讨论】:

  • 输出是否正确? IY 消失了,而 Q 仍然存在?数组 2 的顺序是否相关,还是仅遵循数组 1 的顺序?
  • 我修改了输入输出,让问题更清晰,顺序相关。
  • 在 Wikipedia 文章 en.wikipedia.org/wiki/Sequence_alignment 中,基本上只列出了这些算法。互联网不太可能想出更好的东西。此外,您的问题场景比一般的序列比对情况更简单吗?
  • @Andrew 在我的情况下,性能不是问题。简单是问题,因为它将被翻译成汇编语言。我提到的算法高效快捷,但相当复杂,并且使用动态或加权算法,我无法翻译。我不想重新发明轮子。

标签: java algorithm


【解决方案1】:

使用完全符合您要求的 Levenshtein 距离变化:

输出

-MKNLASREVNIYVNGKLV
QM---ASREVNIYVNGKL-

代码:

public class Main {
    public static void main(String[] args) {
        String[] aligned = align("MKNLASREVNIYVNGKLV", "QMASREVNIYVNGKL");
        System.out.println(aligned[0]);
        System.out.println(aligned[1]);
    }

    public static String[] align(String a, String b) {
        int[][] T = new int[a.length() + 1][b.length() + 1];

        for (int i = 0; i <= a.length(); i++)
            T[i][0] = i;

        for (int i = 0; i <= b.length(); i++)
            T[0][i] = i;

        for (int i = 1; i <= a.length(); i++) {
            for (int j = 1; j <= b.length(); j++) {
                if (a.charAt(i - 1) == b.charAt(j - 1))
                    T[i][j] = T[i - 1][j - 1];
                else
                    T[i][j] = Math.min(T[i - 1][j], T[i][j - 1]) + 1;
            }
        }

        StringBuilder aa = new StringBuilder(), bb = new StringBuilder();

        for (int i = a.length(), j = b.length(); i > 0 || j > 0; ) {
            if (i > 0 && T[i][j] == T[i - 1][j] + 1) {
                aa.append(a.charAt(--i));
                bb.append("-");
            } else if (j > 0 && T[i][j] == T[i][j - 1] + 1) {
                bb.append(b.charAt(--j));
                aa.append("-");
            } else if (i > 0 && j > 0 && T[i][j] == T[i - 1][j - 1]) {
                aa.append(a.charAt(--i));
                bb.append(b.charAt(--j));
            }
        }

        return new String[]{aa.reverse().toString(), bb.reverse().toString()};
    }
}

【讨论】:

  • 太棒了!更简单,更清洁!
  • 介意添加一些解释,说明您的算法与一般序列比对相比没有做什么?
  • 它不能根据操作本身或它们在字符串上的位置为“编辑操作”分配权重。当然,很容易修改它来做到这一点。该算法有一个更通用的版本,称为Smith-Waterman
【解决方案2】:

你对问题的描述立刻让我想到了Levenshtein distance及其相关算法,它很简单(肯定少于50行)但也是基于动态规划的。

原始算法只是计算所需的更改次数,但可以轻松修改它以找到所需的插入、删除和替换。实际上,我不确定您是否甚至想处理替换,例如 ABC 和 ADC,您将如何对齐?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-04
    相关资源
    最近更新 更多