我有一个长文本(大约5 MB文件大小)和另一个名为pattern的文本(大约2000个字符)。
任务是在长文本中找到15个字符或更长的基因组模式的匹配部分。
示例:
长文: ACGTACGTGTCA 的 AAAACCCCGGGGTTTTA GTACCCGTAGGCGTAT 和更长的时间
图案: ACGGTATTGAC 的 AAAACCCCGGGGTTTTA TGTTCCCAG
我正在寻找一种高效(易于理解和实施)的算法。
如果可能的话,奖金将是用C ++中的char数组实现此方法的一种方法。
答案 0 :(得分:7)
这是一个算法 - 我不确定它是否有名字。它需要一个“滚动哈希” - 一个(非加密)哈希函数,它具有给定序列AB...C
的哈希值的属性,计算序列B...CD
的哈希值是有效的。 / p>
计算序列pattern[0..14]
,pattern[1..15]
,pattern[2..16]
的滚动哈希值...并将pattern
中的每个索引存储在哈希表中。
计算haystack[0..14]
的滚动哈希并查看它是否在哈希表中。如果是,请将haystack[0..14]
与pattern[pos..pos+14]
进行比较,其中从哈希表中检索到pos
。
从haystack[0..14]
的滚动哈希中,有效地计算haystack[1..15]
的滚动哈希并查看它是否在哈希表中。重复,直到到达haystack
。
请注意,您的15个字符串只有2个 30 可能的值,因此您的“哈希函数”可以是一个简单的映射到字符串的值,该字符串被视为15位数的base-4数字,计算速度快,具有滚动哈希属性并且是唯一的。
答案 1 :(得分:4)
一种方法是获取Aho-Corasick的实现并使用它来创建能够识别模式中任何15个字符块的内容,然后使用它来搜索文本。使用Aho-Corasick,构建匹配器的成本和搜索成本都是线性的,所以这应该是实用的。
答案 2 :(得分:2)
Stand back,我要直播代码:
void match_substring(const char *a, const char *b, int n) // n=15 in your case
{
int alen = strlen(a); // I'll leave all the null-checking and buffer-overrun business as an exercise to the reader
int blen = strlen(b);
for (int i=0; i<alen; i++) {
for (int j=0; j<blen; j++) {
for (int k; (i+k<alen) && (j+k<blen) && a[i+k]==b[i+k]; k++);
if (k >= n)
printf("match from (%d:%d) for %d bytes\n", i, j, k);
}
}
}
答案 3 :(得分:1)
如果你正在使用C库的一个很好的实现(或者甚至像glibc这样的平庸,实际上很好地实现了这个功能),strstr
会做得很好。我听说有一种新算法对DNA(小字母)特别有用,但我现在找不到参考。除此之外,2way(glibc使用)是最佳的。
答案 4 :(得分:1)
我强烈建议您去图书馆查看Robert Sedgwick和Kevin Wayne撰写的“算法第4版”。他们有一整章专门讨论子串搜索。 此外,可能值得查看图书网站algs4.cs.princeton.edu。
TL; DR - 如果你已经确定,你可以使用字符串数组在保证时间线性到输入长度的情况下进行子字符串搜索。书中和在线都有代码示例。没有那么容易。
答案 5 :(得分:-1)
我认为“后缀树”可以通过O(log n)
的性能更好地解决它