Algorithm 最长共享段算法

Algorithm 最长共享段算法,algorithm,string-matching,Algorithm,String Matching,我有一个相当大的字符串数(1000个),比如S_1…S_n,其中字符只取2个值-比如说为了便于可视化“”(空格)或“_”(下划线) 我想找出两个(或更多)字符串共享相同连续下划线长度的最长长度。在上述情况下,是S_3和S_4之间从位置7到15(含)共享的部分,跨越9个位置 有没有一个有效的算法可以让我找到一对(或更多)这样做的字符串?我不认为这是一个字符串匹配问题,比如最长的公共子字符串问题,因为这些字符串有一个特定的对齐方式 请注意,值得注意的是,这只是一个更大算法的一小部分,该算法重复执行此

我有一个相当大的字符串数(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个字符串。要做到这一点,您必须执行以下操作:

  • 获取每个字符串并为每个_桶创建另一个带有索引对的字符串 例如:对于

  • 取2个字符串的所有组合,并取2个索引(i代表String1,j代表string2)。你要做的是以一种巧妙的方式移动每个索引。首先,两者都是0,在每一步你都会问自己是否可以将索引i的间隔与索引j的间隔相交,这样你就有了这2个间隔的最佳子序列。 完成交叉点后,有两个选项:增加i或增加j

  • a、 如果间隔在j间隔的左边,增加i

    b、 若间隔在i间隔的左边,增加j

    c、 如果他们的左撇子相等,你增加谁并不重要

  • 始终将找到的交叉点与最大值进行比较,如果交叉点较大,则更改最大值
  • 优化: 1.对于每个间隔数组,当您有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