【问题标题】:String Tiling Algorithm字符串平铺算法
【发布时间】:2009-09-17 20:41:41
【问题描述】:

我正在寻找一种有效的算法来进行字符串平铺。基本上,你会得到一个字符串列表,比如 BCDCDEABCA ,结果 tiled 字符串应该是 ABCDE,因为 BCDCDE 对齐产生 BCDE,然后与 @ 对齐987654332@ 产生最终的ABCDE

目前,我正在使用一种稍微幼稚的算法,其工作原理如下。从一对随机字符串开始,比如BCDCDE,我使用以下(在Java 中):

public static String tile(String first, String second) {
  for (int i = 0; i < first.length() || i < second.length(); i++) {
    // "right" tile (e.g., "BCD" and "CDE")
    String firstTile = first.substring(i);
    // "left" tile (e.g., "CDE" and "BCD")  
    String secondTile = second.substring(i);
    if (second.contains(firstTile)) {
      return first.substring(0, i) + second;
    } else if (first.contains(secondTile)) {
      return second.substring(0, i) + first;
    }
  }
  return EMPTY;
}

System.out.println(tile("CDE", "ABCDEF")); // ABCDEF
System.out.println(tile("BCD", "CDE")); // BCDE
System.out.println(tile("CDE", "ABC")); // ABCDE
System.out.println(tile("ABC", tile("BCX", "XYZ"))); // ABCXYZ

虽然这可行,但效率不高,因为它一遍又一遍地迭代相同的字符。

那么,有人知道更好(更有效)的算法来做到这一点吗?这个问题类似于 DNA 序列比对问题,因此非常欢迎该领域(当然还有其他人)提供任何建议。另请注意,我不是在寻找 alignment,而是在寻找 tiling,因为我需要一个字符串完全重叠在另一个字符串上。

我目前正在寻找 Rabin-Karp algorithm 的改编版,以提高算法的渐近复杂度,但在进一步研究此问题之前,我想听听一些建议。

提前致谢。


对于存在歧义的情况 - 例如,{ABC, CBA} 可能导致 ABCBACBABC - 可以返回任何平铺。但是,这种情况很少发生,因为我正在平铺单词,例如{This is, is me} =&gt; {This is me},它们被操纵以使上述算法起作用。

类似问题:Efficient Algorithm for String Concatenation with Overlap

【问题讨论】:

  • +1 表示写得很好的问题(但实际上是为了找到 ï 键 8-)
  • OS X 中的 ï 键是 Alt+u 以获取元音变音符号,然后是应用它的 i

标签: algorithm string tiling


【解决方案1】:

按第一个字符排序字符串,然后是长度(从小到大),然后将适配应用于this question 中关于连接重叠字符串的 KMP。

【讨论】:

  • 谢谢,我正在搜索平铺和对齐,但找不到那个问题。
  • 很难找到它。幸运的是,我已经回答了它,所以它缩小了搜索范围。
【解决方案2】:

我认为这应该适用于两个字符串的平铺,并且比使用子字符串和包含的当前实现更有效。从概念上讲,我遍历“左”字符串中的字符并将它们与“右”字符串中的字符进行比较。如果这两个字符匹配,我将移动到正确字符串中的下一个字符。根据首先到达末尾的字符串,以及最后比较的字符是否匹配,确定可能的平铺情况之一。

我还没有想到任何可以提高平铺两个以上字符串的时间复杂度的方法。作为多个字符串的一个小注释,下面的这个算法很容易扩展为一次检查单个“左”字符串与多个“右”字符串的平铺,如果你试图的话,这可能会防止额外的字符串循环通过尝试所有的可能性来找出是做 ("ABC", "BCX", "XYZ") 还是 ("ABC", "XYZ", BCX")。一点点。

string Tile(string a, string b)
{
    // Try both orderings of a and b,
    // since TileLeftToRight is not commutative.

    string ab = TileLeftToRight(a, b);

    if (ab != "")
        return ab;

    return TileLeftToRight(b, a);

    // Alternatively you could return whichever
    // of the two results is longest, for cases
    // like ("ABC" "BCABC").
}

string TileLeftToRight(string left, string right)
{
    int i = 0;
    int j = 0;

    while (true)
    {
        if (left[i] != right[j])
        {
            i++;

            if (i >= left.Length)
                return "";
        }
        else
        {
            i++;
            j++;

            if (i >= left.Length)
                return left + right.Substring(j);

            if (j >= right.Length)
                return left;
        }
    }
}

【讨论】:

    【解决方案3】:

    如果开源代码是可以接受的,那么您应该检查斯坦福STAMP 基准套件中的基因组 基准:它几乎完全符合您的要求。从一堆字符串(“基因”)开始,它寻找包含所有基因的最短字符串。例如,如果您有 ATGC 和 GCAA,它会找到 ATGCAA。算法并没有将其限制为 4 个字符的字母表,所以这应该可以帮助您。

    【讨论】:

      【解决方案4】:

      首先要问的是要不要找{CDB, CDA}的耕种?没有单一的耕作。

      【讨论】:

      • 不,我需要其中一个字符串完全重叠。使用我的算法,那对字符串将返回 EMPTY 字符串。
      • 一个简单的近似算法是建立一个 de bruijn 图。我在想别人。
      • @Lasse V. Karlsen:这是一个有趣的案例,因为有两种可能的组合(“ABC”+“CDE”或“ABC”+“CFG”)。但是考虑一个成对的字符串平铺。
      • 这对 {ABC, CBA} 的输出是什么?由于模棱两可而空置?这个 {ABC, BCA} 怎么样?更喜欢ABCA,因为重叠时间更长?你允许不完美的匹配吗?如果不全面了解您的问题,就很难走得更远。
      • @lh3:分别为“ABCBA”和“ABCA”。基本上,我首先尝试在“右侧”平铺,然后在“左侧”平铺。我没有考虑这些情况,因为我实际上是在拼写单词(例如“国王”和“国王是”=>“国王是”),但我简化了我的例子,因为我认为它更容易解释.不完美的匹配是什么意思?感谢您的关注,顺便说一句。
      【解决方案5】:

      有趣的问题。你需要某种回溯。例如,如果您有:

      ABC, BCD, DBC 
      

      将 DBC 与 BCD 结合会得到:

      ABC, DBCD
      

      这是无法解决的。但是将 ABC 与 BCD 结合会导致:

      ABCD、DBC

      可以组合成:

      ABCDBC.
      

      【讨论】:

      • 是的,我需要深入研究。另一种方法是生成字符串的所有n! 排列,然后为每个可能的排列从左到右进行,但这显然非常慢。
      猜你喜欢
      • 2012-02-12
      • 2015-12-03
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      相关资源
      最近更新 更多