做一个无前缀的集合
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(总大小))的两遍算法。我不会进一步更新我的答案,因为它已经发生了很大的变化,但如果你把它作为答案,我会很高兴地支持你的建议。以上是关于做一个无前缀的集合的主要内容,如果未能解决你的问题,请参考以下文章