【问题标题】:Longest substring that matches a string in an array与数组中的字符串匹配的最长子字符串
【发布时间】:2016-07-13 22:09:12
【问题描述】:

假设我有以下输入并且我的实现语言是 Java:

  • 一个数组,A,内容为:["brown fox", "jumped over the", "lazy dog", "dog", "the", "fish", "quantum burrito", "ox jumped over the laz", "and ate", "ate pie"]

  • 一个字符串,S,内容为:"the quick brown fox jumped over the lazy dog and ate pie"(第一个字符索引 0,最后一个字符索引 55)

我需要(在典型计算机上尽可能高效地)组装字符串 S 的子字符串列表,这些子字符串(完全)包含在数组 A,并按降序排列。我还需要知道每个匹配的字符串 S 中的开始和结束字符索引。 ...但有一些限制。

以下限制和特殊性适用于这个问题:

  • 并非数组 A 中的所有元素都可以包含在字符串 S 中(在示例中,“fish”和“quantum burrito”不在 中S)。
  • 字符串 S 可能包含与数组中的任何元素都不匹配的字符长度(在示例中,S 中的“quick”与一个)。
  • S中尊重单词边界(保证两个A中的单词恰好用一个空格分隔S);意思是,如果 S 中的字符长度与 A 匹配,但由于未捕获一个或多个 而违反了单词边界,则 不是 匹配整个单词
  • 当长度相同时,结果数组中的排序顺序无关紧要。
  • 一旦匹配 S 中的一系列字符,该范围将仅在一个结果元素中捕获,即使它可以匹配 A 中的多个元素。李>
  • 如果有两个可能的匹配项,请根据算法处理数组中元素的顺序任意选择一个。
  • 我需要跟踪算法完成后哪些字符范围没有匹配。

仅通过查看字符串和数组手动解决此问题,在此示例中,解决方案如下,以正确的降序(从零开始的索引)给出:

  1. 字符范围 [20..34](“跳过”)位于数组的索引 1 中。长度 = 15
  2. 字符范围 [10..18](“棕狐”)在数组的索引 0 中。长度 = 9
  3. 字符范围 [36..43](“lazy dog”)在数组的索引 2 中。长度 = 8
  4. 字符范围 [49..55](“ate pie”)在数组的索引 9 中(任意匹配;匹配“and ate”同样有效,但我们没有t 匹配 both 因为“ate”已经“consumed”;没有双关语的意思)。长度 = 7
  5. 字符范围 [0..2](“the”)在数组的索引 4 中。长度 = 3
  6. 单词“quick”与数组中的任何元素都不匹配。
  7. 单词“and”与数组中的任何元素都不匹配。

注意,具体来说,“ox jumped over the laz”,虽然它是 A 中最长的子字符串,它在 S 内,但 不是 strong> 在结果集中匹配,因为它违反了“fox”和“lazy”的单词边界。

问题:我是在描述一个可能存在于库中的相当标准的算法(部分或全部;我愿意用更简单的原始构建块构建它)还是这样我需要从头开始实现它的自定义?

如果我从头开始实现它,我认为我需要采用大致如下的方法:

  • 在单词边界上拆分字符串S
  • 构造一个列表L,其中包含字符串S中的所有(按顺序排列的)单词序列,按长度降序排列(例如:["the quick brown fox jumped over the lazy dog and ate pie", "the quick brown fox jumped over the lazy dog and ate", "quick brown fox jumped over the lazy dog and ate pie", ... "the quick brown fox jumped", ... "brown fox jumped", ... "jumped", "quick", "brown", ... "pie"])。李>
  • 从数组A的内容构造一个后缀树T
  • 依次遍历列表L,并尝试找到T中的每个元素
  • 一旦找到一个元素,记下从S开始的子串范围,从A开始的匹配索引,然后继续迭代
  • 每次匹配一个元素时,如果该元素匹配的字符范围索引与已匹配的元素重叠,则跳过并继续

听起来很慢......而且可能很难做到正确。

【问题讨论】:

    标签: java string algorithm


    【解决方案1】:

    您可以轻松地做到这一点仅依靠正则表达式。虽然以下是示范性的,不符合广泛的请求列表(即将结果放入数组并对其进行排序),但实现起来很简单。

    “棘手”部分是单词边界分隔符 \b 并使用组 () 来捕获您想要匹配的实际组。

    String[] A = {"brown fox", "jumped over the", "lazy dog", "dog", "the", "fish", "quantum burrito", "ox jumped over the laz", "and ate", "ate pie"};
    String S = "the quick brown fox jumped over the lazy dog and ate pie";
    
    for(String s : A) {
        Pattern p = Pattern.compile(".*\\b(" +s+ ")\\b.*");
        Matcher m = p.matcher(S);
    
        while (m.find()) {
            System.out.println(m.matches() + " => " + s);
            System.out.println("    Start index: " + m.start(1));
            System.out.println("    End index: " + m.end(1));
            System.out.println("    Length: " + m.group(1).length());
        }
    }
    

    上面匹配所有包含的字符串,只要它们是空格分隔的,并输出它们在主字符串中的开始/结束位置。

    【讨论】:

      猜你喜欢
      • 2014-06-26
      • 2022-06-10
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      相关资源
      最近更新 更多