Algorithm 最长共享段算法
我有一个相当大的字符串数(1000个),比如S_1…S_n,其中字符只取2个值-比如说为了便于可视化“”(空格)或“_”(下划线) 我想找出两个(或更多)字符串共享相同连续下划线长度的最长长度。在上述情况下,是S_3和S_4之间从位置7到15(含)共享的部分,跨越9个位置 有没有一个有效的算法可以让我找到一对(或更多)这样做的字符串?我不认为这是一个字符串匹配问题,比如最长的公共子字符串问题,因为这些字符串有一个特定的对齐方式 请注意,值得注意的是,这只是一个更大算法的一小部分,该算法重复执行此操作,将共享长度合并在一起形成一个新字符串,因此在下一次迭代中,我将Algorithm 最长共享段算法,algorithm,string-matching,Algorithm,String Matching,我有一个相当大的字符串数(1000个),比如S_1…S_n,其中字符只取2个值-比如说为了便于可视化“”(空格)或“_”(下划线) 我想找出两个(或更多)字符串共享相同连续下划线长度的最长长度。在上述情况下,是S_3和S_4之间从位置7到15(含)共享的部分,跨越9个位置 有没有一个有效的算法可以让我找到一对(或更多)这样做的字符串?我不认为这是一个字符串匹配问题,比如最长的公共子字符串问题,因为这些字符串有一个特定的对齐方式 请注意,值得注意的是,这只是一个更大算法的一小部分,该算法重复执行此
S_1: _______ ____ __ _____ ___
S_2: _______ _____ ___
S_3: ____
S_4: ____ ___
S_N+1: _________
然后我会重复这个算法,发现(在本例中)S_2和新的S_N+1共享下一个最长的部分,从位置11-15,形成
S_1: _______ ____ __ _____ ___
S_2: _______ ___
S_3: ____
S_4: ____ ___
S_N+1: ____
S_N+2: _____
然后S_1、S_2和S_3从位置3-6共享一个截面,给出
S_1: ___ ____ __ _____ ___
S_2: ___ ___
S_3:
S_4: ____ ___
S_N+1: ____
S_N+2: _____
S_N+3: ____
依此类推首先,答案总是在两个字符串之间。如果“其中2个(或更多)字符串共享相同的连续下划线长度,”是正确的要求,则不可能有2个以上的字符串具有比最佳匹配的2个更长的序列。 因此,问题在于找到在同一位置上具有最长序列的最长2个字符串。要做到这一点,您必须执行以下操作:
它的复杂性是O(N^2*(O(len(S1)+len(S2)+…+len(Sn)),因为只有第1步遍历所有字符,而第2步遍历间隔。我将假设所有字符串的长度相同,尽管您可以根据需要填充它们以使其工作 有一个整数数组a,长度与字符串相同,初始化为all-1。a[i]的值将是使用所有下划线从i可以达到的最大索引。也就是说,如果a[i]==k,则该字符串中的某个[i]..k完全是下划线
bestOverall := -1
For each string, S:
maxPos := -1
for i := len(S); i >= 0; i--:
if S[i] == '_' && maxPos < 0:
// We were previously look at ' ', now we're looking at '_', so store
// the highest index that happened at in this particular run.
maxPos = i
if S[i] == ' ':
maxPos = -1
if min(A[i]-i, maxPos-i) > bestOverall:
// This is the crux of it all. A[i]-i is the length of consecutive '_'
// you've seen in a single string before, starting at this position.
// maxPos-i is the length of consecutive '_' you've seen in this string,
// starting at this position. If this length is greater than your
// previous best, keep track of it. Presumably you also might want to
// store which strings were involved, which would take extra storage.
bestOverall = min(A[i]-i, maxPos-i)
if maxPos >= A[i]:
// If you're doing better with this string than previous iterations,
// keep track of it.
A[i] = maxPos
besttotal:=-1
对于每个字符串,S:
maxPos:=-1
对于i:=len(S);i>=0;i--:
如果S[i]=''\'&&maxPos<0:
//我们以前看的是“”,现在看的是“”,所以
//此特定运行中在发生的最高索引。
maxPos=i
如果S[i]='':
maxPos=-1
如果min(A[i]-i,maxPos-i)>最佳总体:
//这就是问题的症结所在。A[i]-i是连续'\u1'的长度
//您以前在单个字符串中看到过,从这个位置开始。
//maxPos-i是您在该字符串中看到的连续“u”的长度,
//从该位置开始。如果该长度大于
//以前最好的,记住它。想必你也会想要的
//存储涉及的字符串,这将占用额外的存储空间。
最佳总体=最小值(A[i]-i,最大位置-i)
如果maxPos>=A[i]:
//如果使用此字符串比以前的迭代做得更好,
//跟踪它。
A[i]=maxPos
在本次best的结尾,将是使用两个字符串可以得到的最长下划线。您可以保留一个辅助数组来跟踪涉及的第一个字符串,并在每次更新best时存储涉及的第一个和第二个字符串。这是O(N*S),其中N是字符串的数量,S是字符串的长度。假设字符串采用这种格式,而不是间隔列表,这是最好的选择。如果它们是间隔列表,那么您可能会做得更好。这不是一个真正聪明或快速的解决方案,但可能会有所帮助。将字符串转换为二进制数然后使用
和(按位操作)对它们进行比较,然后遍历新创建的数组,找到最长的1或0。是的,直到达到最大位长度。不过,我假设有库允许任意长度的位数组。请注意,我很乐意通过存储间隔而不是字符串本身来实现这一点(事实上,字符串只是集合列表中某些数字的存在或不存在的表示。“2.取2个字符串的所有组合”-这难道不使该算法至少为O(n^2)?是的,它是O(n^2*(O(len(S1)+len(S2)+len(Sn)))。另外,现在我在想一个更快的解决方案可能就是将所有间隔放在一个数组中,然后遍历它们并发生2个事件:0。按起始点对间隔进行排序1。如果到达起始点,则将间隔的起始点添加到队列中。2.从队列中删除间隔,然后到达终点
bestOverall := -1
For each string, S:
maxPos := -1
for i := len(S); i >= 0; i--:
if S[i] == '_' && maxPos < 0:
// We were previously look at ' ', now we're looking at '_', so store
// the highest index that happened at in this particular run.
maxPos = i
if S[i] == ' ':
maxPos = -1
if min(A[i]-i, maxPos-i) > bestOverall:
// This is the crux of it all. A[i]-i is the length of consecutive '_'
// you've seen in a single string before, starting at this position.
// maxPos-i is the length of consecutive '_' you've seen in this string,
// starting at this position. If this length is greater than your
// previous best, keep track of it. Presumably you also might want to
// store which strings were involved, which would take extra storage.
bestOverall = min(A[i]-i, maxPos-i)
if maxPos >= A[i]:
// If you're doing better with this string than previous iterations,
// keep track of it.
A[i] = maxPos