Javascript 什么';在两个(或更多)数组中查找匹配的单元格序列的最有效方法是什么?
示例1 假设我有两个数组:Javascript 什么';在两个(或更多)数组中查找匹配的单元格序列的最有效方法是什么?,javascript,arrays,algorithm,pattern-matching,Javascript,Arrays,Algorithm,Pattern Matching,示例1 假设我有两个数组: ('n','v','a','n','i','n','n','v','a','n') ('a','n','n','n','v','a','n','v','n') 我想找到这两个(可能超过两个单元格长度)之间的所有匹配序列,它们不是其他更长匹配的子匹配。以下是我所看到的匹配: ('n','n','v','a','n')=数组1中的位置5和数组2中的位置3 数组1:('n','v','a','n','i','n','n','v','a','n') 数组2:('a','n'
('n','v','a','n','i','n','n','v','a','n')
('a','n','n','n','v','a','n','v','n')
我想找到这两个(可能超过两个单元格长度)之间的所有匹配序列,它们不是其他更长匹配的子匹配。以下是我所看到的匹配:
('n','n','v','a','n')
=数组1中的位置5和数组2中的位置3
数组1:('n','v','a','n','i','n','n','v','a','n')
数组2:('a','n','n','n','v','a','n','v','n')
示例2
('n','v','a','n','i','n','n','v','i','n')
('a','n','i','n','p','v','i','n','v','n')
在这里,我们有多个序列,但它们较短,如下所示:
('a','n','i','n')
=数组1中的位置2和数组2中的位置0
('v'、'i'、'n')
=数组1中的位置7和数组2中的位置5
数组1:('n','v','a','n','i','n','a','v','i','n')
数组2:('a'、'n'、'i'、'n'、'p'、'v'、'i'、'n'、'v'、'n')
摘要
两个示例中都有多个匹配项,但它们都存在于至少一个数组中的较大匹配项中
那么,能够实现这一点的最有效的(低内存和高速的平衡,想想移动设备)代码是什么?JavaScript代码示例将非常棒 这是一个O(n)O(n+k)解,用于两个字符串A
和B
,其长度总和为n,并且具有k个这样的最大匹配子字符串:
a
和B
上构建a。(这只是单个字符串A$B#
上的普通后缀树,其中$
和#
是单个字符,它们在A
或B
中的任何位置都不会出现)这可以使用例如Ukkonen算法在O(n)时间内完成- 确定并记录此节点下方是否存在与后缀
对应的叶,以及此节点下方是否存在与后缀a
对应的叶。(练习:如何回答树叶的这个问题?)B
- 如果这两种叶子都存在,并且对于任何子节点都不是这样,则将与此节点对应的子字符串作为解决方案报告。(如果该条件也适用于某个子字符串,则与此节点对应的子字符串是与该子字符串对应的子字符串的子字符串,并且您只需要最大子字符串。)
这也适用于较小的字符串数>=3:计算并存储当前节点下有叶子的输入字符串集,当该集满时“激发”。如果这两个数组的长度分别为
m
和n
,我认为你不可能做得比O(mn)更好
在一般情况下。假设数组中有交替的a
s字符,但其他字符不同,如下所示
[a, b, a, c, a, d, a, e, a, f, a, g]
[a, h, a, i, a, j, a, k, a, l, a, m]
匹配数为(m/2)*(n/2)
。如果您想找到所有这些,您的算法最多只能是O(mn)
您可以在O(mn)
时间内完成,如下所示。想象一下这样将一个阵列滑过另一个阵列:
[a, b, c, d, e]
[f, g, h, i, j]
[a, b, c, d, e]
[f, g, h, i, j]
[a, b, c, d, e]
[f, g, h, i, j]
...
[a, b, c, d, e]
[f, g, h, i, j]
有m+n-1
可能的位置。对于每个位置,您必须迭代对齐字符对(这些字符对中最差的min(m,n)
),并找到匹配字符的最长链。这具有时间复杂性
O((m + n) * min(m, n)) = O(mn)
这种解决方案的缺点是所花费的时间实际上只取决于数组的长度,而不取决于内容。例如,即使数组相等,仍然需要
O(nm)
时间(显然只需要O(n)
时间来检查并返回一个答案)。如另一个答案所示,如果匹配序列的数量很小,则会有更聪明的解决方案,所需时间会少得多。下面是我在通用LCS上的JavaScript尝试,O(mn)
时间和空间,版本。因为我们一行一行地进行,所以只需重用两行,完成后将第二行复制到第一行,就可以减少空间
var example1=[[n'、'v'、'a'、'n'、'i'、'n'、'n'、'v'、'a'、'n']
,[a',n',n',n',v',a',n',v',n',n'],
示例2=[[n'、'v'、'a'、'n'、'i'、'n'、'n'、'v'、'i'、'n']
,[a',n',i',n',v',i',n',v',n',n'];
功能f(as){
var M=新数组(作为[0]。长度),
结果=[];
对于(var i=0;I1&&j>1&&M[i][j]2){
结果.推送([i-M[i-1][j-1],j-M[i-1][j-1],M[i-1][j-1]);
}
}
}
返回结果;
}
console.log(JSON.stringify(f(example2));//[[2,0,4],[6,3,4]]
如果您不理解我的问题,或者可能会更清楚,请发表评论!不要只是否决投票!请发布您的尝试…您尝试了什么?@brso05我还没有完成任何代码。。。我脑子里有一些随机的东西,很难用文字或代码表达出来。对不起,我没有什么要说的了@马修:啊,我明白了。看起来你面临的问题是,有各自的解决方案。@Matthew:不,计算机科学知道有很多更棘手的问题:-)我不知道如何将其编码成Javascript。想用例子解释一下吗?我讨厌人们也匿名投票,但也许他们还不能发表评论什么的?@Matthew:恐怕我不知道。可能存在可用的库。你是对的,一般来说,你不能比O(mn)做得更好(很好的构造)。但是你仍然可以做得更好,因为你可以制作一个输出敏感的算法,即O(f(n,m)+k,f(n,m)是O(mn)。@j_random_hacker这是真的。你知道O(f(n,m)+k)
算法的平均时间复杂度是多少吗?上述方法的缺点是,它基本上总是需要相同的时间