【问题标题】:Get a string with highest amount of prefixes获取前缀数量最多的字符串
【发布时间】:2017-02-13 19:59:59
【问题描述】:

我有一个字符串列表,例如:

py
python
co
comp
computer

我只是想得到一个字符串,它包含尽可能多的前缀。结果应该是“computer”,因为它的前缀是“co”和“comp”(2 个前缀)。

我有这个代码(wordlist 是字典):

for i in wordlist:
    word = str(i)
    for j in wordlist:
        if word.startswith(j):
            wordlist[i] += 1
result = max(wordlist, key=wordlist.get)

有没有更好、更快的方法来做到这一点?

【问题讨论】:

  • 一项改进是删除word = str(i) 部分,只删除变量i。如果i 已经是字符串,则没有理由对其进行转换。除非我遗漏了一些非常明显的东西......
  • 你也许可以使用基数树,但我认为这仍然是 O(n^2)
  • @PatrickHaugh 为什么会是 O(n**2)?您可以简单地遍历所有叶子并计算叶子和根节点之间的终端节点。
  • @EricDuminil 您还必须构建树。我认为这是最坏的情况 n**2
  • @PatrickHaugh 它是 O(m*n),其中 n 是单词数,m 是平均单词长度。在上述情况下,m 可能是有界的,所以它是 O(n)

标签: python string performance python-3.x prefix


【解决方案1】:

您要查找的数据结构称为trie。关于这种搜索树的维基百科文章当然值得一读。在这里派上用场的 trie 的关键属性是:

一个节点的所有后代都有一个与该节点关联的字符串的公共前缀,而根与空字符串关联。

代码如下:

words = """py
python
co
comp
computer""".split()

def make_trie(ws):
    """Build trie from word list `ws`."""
    r = {}  # trie root
    for w in ws:
        d = r
        for c in w:
            d = d.setdefault(c, {})  # get c, set to {} if missing
        d['$'] = '$' # end marker
    return r

def num_pref(t, ws):
    """Use trie `t` to find word with max num of prefixes in `ws`."""
    b, m = -1, ''  # max prefixes, corresp. word
    for w in ws:
        d, p = t, 1
        for c in w:
            if '$' in d: p += 1
            d = d[c]  # navigate down one level
        if p > b: b, m = p, w
    return b, m

t = make_trie(words)
print(num_pref(t, words))

make_trie 构建 trie,num_pref 使用它来确定具有最大前缀数的单词。它打印(3, 'computer')

显然,这两种方法可以结合使用。我将它们分开以使构建 trie 的过程更加清晰。

【讨论】:

  • make_trie 非常紧凑。更新:它也与我的答案中的链接完全相同。
【解决方案2】:

对于大量的单词,您可以构建一个trie

然后您可以遍历所有叶子并计算具有根和叶子之间值的节点(终端节点)的数量。

与您的O(n**2) 解决方案相比,这需要O(n) 步骤。

这个package 看起来不错,这是一个相关的thread

【讨论】:

    【解决方案3】:

    “正确”的方法是使用某种 trie 数据结构或类似的。但是,如果您的单词已经排序,则可以通过一些相当简单的代码(使用前缀堆栈而不是蛮力搜索)在实际中获得相当大的加速。这是有效的,因为按排序顺序,所有前缀都在其前缀词之前(通过简单的线性扫描很容易获得结果)。将其视为简单代码和高效代码之间的合理折衷:

    prefixes = []   # Stack of all applicable prefixes up to this point (normally very small)
    max_prefixes = [None]
    for w in sorted(wordlist):
        while prefixes and not w.startswith(prefixes[-1]):
            prefixes.pop()
        prefixes.append(w)
        if len(prefixes) >= len(max_prefixes):
            max_prefixes = list(prefixes)
    result = max_prefixes[-1]
    

    在我的 Linux 机器上运行所有字典单词(其中 479828 个),上面的代码只需要 0.68 秒(原始代码没有在合理的时间内完成)。在前 10000 个单词中,我的代码采用 0.02s 而不是原始代码采用的 19.5s

    如果您想要真正高效的代码(例如,您正在处理千兆字节的数据),您最好使用以 C 语言以缓存友好的方式编码的适当数据结构。但这可能需要数周才能正确编写!

    【讨论】:

      猜你喜欢
      • 2016-06-22
      • 1970-01-01
      • 1970-01-01
      • 2016-04-28
      • 2018-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      相关资源
      最近更新 更多