【问题标题】:Length of the shortest phrase with given keywords in a large text大文本中给定关键字的最短短语的长度
【发布时间】:2012-05-08 05:38:00
【问题描述】:

这个问题是在一次采访中向我的一位朋友提出的。

给定两个关键字,我们必须在大文本中找到具有给定关键字的最短短语的长度。 关键字可以在该文本中以任何顺序出现。 约束:保持高效的数据结构,这样每次文本都不需要解析不同关键字的查询

例如。关键词:“一”、“四” 文字:“一二三四五四六 一个”

这里最短的短语是“四六一”而不是“一二 三四”

我们想到的解决方案是: 用文本的所有单词构建了一个 BST。每个节点维护单词的位置。 (这将是一个排序列表)当查询来搜索 [O(logn)] 两个词时,找到它们在 [O(n)] 中的位置之间的最小差异,从而使其有效地 [O(nlogn)]。

我们可以做得更好吗?

【问题讨论】:

  • 你是如何从 O(log n) 操作和 O(n) 操作中获得 O(n log n) 的?那是 O(n)。但是第二个操作实际上不是 O(n),它是 O(# of word matches),根据数据分布,可能小于 O(n)。
  • 是的 :) 我错了!它是 O(n) Regd。第二个操作。两次搜索都会产生一个排序的位置数组,找到它们之间的最小距离。是的,它是 O(关键字在文本中出现的次数)

标签: algorithm data-structures


【解决方案1】:

您可以将哈希表用于反向索引,即从单词(关键字)到其在文本中位置的排序列表的哈希表。得到查询的两个关键字后,查找它们的关联记录就是O(1)操作。

找到发生位置之间的最小差异是 O(k) 操作,其中 k 是较长的发生列表的长度。在异常情况下,可能是 k 接近于 n,但在实际使用中并非如此(除非您使用“the”和“a”作为两个关键字,但是这些类型的词,称为停用词,通常被排除在完整的无论如何文本搜索)。

在通常的设置中,k 与 n 相比非常小,所以这应该非常快,即 O(1) + O(更常见关键字的出现次数)。

【讨论】:

    【解决方案2】:

    看来这可以使用Dynamic Programming 解决。在不失一般性的情况下,我可以将问题重新表述为:

    给定搜索空间S = {s1, s2, ..., sn},针对(si, sj),我们必须找到位置对(k, l),这样:

    1. (sk, sl) == (si, sj)
    2. distance(k, l) 是最小值。

    该问题的递归解决方案可以通过以下方式制定:

    Cost(m) =

    1. LARGEST_NUMBER, if m = 0
    2. Min (Cost(m-1), distance(S[m], Latest_si)), if m > 0 and S[m] == sj
    3. Min (Cost(m-1), distance(S[m], Latest_sj)), if m > 0 and S[m] == si
    4. Cost(m-1), if m > 0 and S[m] != (si, sj)

    在哪里,

    1. Cost(m) 是优化函数。它表示搜索空间S[1:m](si, sj) 之间的最小距离。
    2. Latest_sisi的最新位置。
    3. Latest_sjsj的最新位置。

    这可以转换为空间复杂度为O(n)O(n) 自底向上循环来存储Cost

    这是上述算法在 Python 中的实现:

    def min_phrase (S, si, sj):
      Cost = []
      for i in S:
        Cost.append([len(S), [-1, -1]])
    
      latest_si = -1
      latest_sj = -1
    
      for idx, v in enumerate(S):
        if v == si:
          if latest_sj >=0:
            cost = idx - latest_sj
            if cost < Cost[idx - 1][0]:
              Cost[idx] = [cost, [latest_sj, idx]]
            else:
              Cost[idx] = Cost[idx - 1]
          else:
            Cost[idx] = Cost[idx - 1]
    
          latest_si = idx
    
        elif v == sj:
          if latest_si >=0:
            cost = idx - latest_si
            if cost < Cost[idx - 1][0]:
              Cost[idx] = [cost, [latest_si, idx]]
            else:
              Cost[idx] = Cost[idx - 1]
          else:
            Cost[idx] = Cost[idx - 1]
    
          latest_sj = idx
    
        else:
          Cost[idx] = Cost[idx - 1]
    
      return Cost[len(S) - 1]
    
    
    if __name__ == '__main__':
      S = ("one", "two", "three", "four", "five", "four", "six", "one")
      si = "one"
      sj = "four"
    
      result = min_phrase(S, si, sj)
      if result[1][0] == -1 or result[1][1] == -1:
        print "No solution found"
      else:
        print "Cost: {0}".format(result[0])
        print "Phrase: {0}".format(" ".join(S[result[1][0] : result[1][1] + 1]))
    

    【讨论】:

      【解决方案3】:

      首先将文本拆分为短语。为这些短语中的每一个分配一个数字。现在文本中的每个单词都出现在其中一些短语中。将短语长度放入数组中。将单词放入哈希表中,将它们出现在其中的短语数作为有序数组。

      现在,当我们想要包含两个单词的最短短语时,首先获取单词的两个 prase-array,然后进行集合交集,然后查找结果短语编号的短语长度。选择最短的。

      【讨论】:

      • 您只能解析文本一次。那么你怎么知道一个词组是什么?
      • 由于问题表明您必须找到包含这两个词的最短短语,因此您可以假设存在将文本拆分为这些短语的规则。
      【解决方案4】:

      我可能错过了重点,但这看起来可以使用 O(n) 中的简单 String[] text 数组而不是一些花哨的数据结构来完成。

      • 1* 将文本加载到数组中。
      • 2* 找到关键字x 的位置并跟踪其位置。
      • 3* 找到关键字y 的位置并跟踪其位置。
      • 4* 标记 x 和 y 之间的距离。
      • 5* 第一次设置minx = xminy = y
      • 6* 不断寻找 x 和 y,交替寻找,每次找到新的更小的距离时都会改变 minx 和 miny 的值。
      • 7*最终返回以minx和miny为界的子串

      【讨论】:

        猜你喜欢
        • 2019-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-11
        • 2014-02-25
        相关资源
        最近更新 更多