做一个无前缀的集合

Posted

技术标签:

【中文标题】做一个无前缀的集合【英文标题】:Make a set prefix-free 【发布时间】:2016-01-25 02:52:24 【问题描述】:

是否有标准或最佳算法可以使给定的字符串集无前缀?也就是说,给定一组字符串,丢弃所有在该集合中也具有(较短)前缀的字符串。

如果这很重要,我最终会在 Python 2.7 中实现它。

【问题讨论】:

你能给出一个期望输出的示例输入吗? 多少个多长的字符串? @StefanPochmann 取决于。在输入 $n$ 上,它们是长度最多为 $n$ 的二进制字符串,并且最多有 $2^n$ 个。除此之外,有多少和多长时间是随机的(根据一些未知的分布)。 【参考方案1】:
strings = ['a', 'apple', 'b', 'beta', 'c', 'd']

def prefices_only(strlist):
    ordered = sorted(strlist)
    last = ordered[0]
    results = [last]

    for c in ordered:
        if not c.startswith(last):
            last = c
            results.append(c)

    return results

print(prefices_only(strings))

【讨论】:

@j_random_hacker: No it doesn't. 你忘记了last 在丢弃字符串时不会更新。关键的见解是,如果ordered[i]ordered[j] 的前缀,那么ordered[i+1:j-1] 的所有元素也有ordered[i] 作为前缀。此外,startswith 比较最多检查输入的每个字母两次,因此将其称为二次时间是一种误导。如果是 O(n^2),那么 O(n*log(n)) 时间是不可能的;这似乎是可能的,因为您为排序中涉及的比较分配了太低的成本。 (抱歉 - 为尝试插入分配的成本太低。) @user2357112:在两件重要的事情上你是对的(我错了)——这里的算法是正确的,startsWith 只做线性的工作。稍后我将进行编辑并 +1。 OTOH 我没有为我的算法声称 O(n log n) 时间,这显然是不可能的——我声称时间与输入的总大小成正比(可能令人困惑的是,我没有用任何“字母”命名变量),除非 O(n log n) 已经比这更糟了。 (n 只是我答案中的字符串数。) last不总是和results[-1]一样,这样就不需要了吗?如果您使用results = ordered[:1] 进行初始化,那么您也不会像现在这样因为空输入而崩溃。【参考方案2】:

[编辑:丢弃(不是)前缀的字符串]

    按长度递增的顺序对字符串进行排序。 将每个字符串插入trie。如果插入一个字符会为当前无子节点(即叶子)创建一个新的子节点,则丢弃当前字符串——它有一个前缀。

[编辑:固定时间复杂度]

第一步需要 O(n log n) 时间来对 n 个字符串进行排序。如果平均字符串长度超过 log(n),那么这个时间复杂度由第二步控制,这需要时间(和空间)与所有输入字符串的总大小成线性关系。它也很容易实现。

【讨论】:

以前从未听说过“trie”,必须阅读一下。看起来您的算法正在丢弃前缀而不是扩展名;我想保留前缀(较短的)。 @QuinnCulver:哎呀,我现在已经修复了算法。还添加了“trie”链接。 似乎排序步骤并不是真正需要的。如果 trie 插入结束于内部节点,我们可以丢弃该节点的后代并使其成为叶子。 @StefanPochmann:字符串的数量。 ("对 n 个字符串进行排序") @user2357112:好主意!这将产生一个简单且渐近更快(O(总大小))的两遍算法。我不会进一步更新我的答案,因为它已经发生了很大的变化,但如果你把它作为答案,我会很高兴地支持你的建议。

以上是关于做一个无前缀的集合的主要内容,如果未能解决你的问题,请参考以下文章

P1666 前缀单词

1280 前缀后缀集合(map)

C++ Boggle Solver:在集合中查找前缀

KMPnext数组自看

Mondodb

freeRTOS与裸机程序相比有什么区别??