我有一个像
这样的字符串列表我想找到一组最短的子序列,这些子序列对于集合中的每个字符串都是唯一的;每个子序列中的字符不需要相邻,只是它们出现在原始字符串中的顺序。对于上面的例子,那将是(沿着其他可能性)
Fb
(正如 Foobar 所独有的;与 Foobaron 的碰撞不可避免)Fn
( Foobaron独有,没有其他...F...n...
)Ft
( Foot )bs
( barstool )bf
( barfoo )e
( footloose )是否有一种有效的方法来挖掘这些序列并最小化碰撞字符串的数量(当无法避免碰撞时,例如当字符串是其他字符串的子串时)来自给定的字符串数组?更确切地说,选择长度N,最多N个字符的子序列集是什么,每个字符用于识别具有最少数量冲突的原始字符串。
答案 0 :(得分:4)
我不会称之为“高效”,但你可以做得比那样完全愚蠢:
words = ['Foobar', 'Foobaron', 'Foot', 'barstool', 'barfoo', 'footloose']
N = 2
n = len(words)
L = max([len(word) for word in words])
def generate_substrings(word, max_length=None):
if max_length is None:
max_length = len(word)
set_substrings = set()
set_substrings.add('')
for charac in word:
new_substr_list = []
for substr in set_substrings:
new_substr = substr + charac
if len(new_substr) <= max_length:
new_substr_list.append(new_substr)
set_substrings.update(new_substr_list)
return set_substrings
def get_best_substring_for_each(string_list=words, max_length=N):
all_substrings = {}
best = {}
for word in string_list:
for substring in generate_substrings(word, max_length=max_length):
if substring not in all_substrings:
all_substrings[substring] = 0
all_substrings[substring] = all_substrings[substring] + 1
for word in string_list:
best_score = len(string_list) + 1
best[word] = ''
for substring in generate_substrings(word=word, max_length=max_length):
if all_substrings[substring] < best_score:
best[word] = substring
best_score = all_substrings[substring]
return best
print(get_best_substring_for_each(words, N))
该程序打印解决方案:
{'barfoo': 'af', 'Foobar': 'Fr', 'Foobaron': 'n', 'footloose': 'os', 'barstool': 'al', 'Foot': 'Ft'}
这仍然可以通过常数因子轻松改进,例如存储generate_substrings
的结果而不是计算两次。
复杂度为O(n*C(N, L+N))
,其中n是单词的数量,L是单词的最大长度,C(n, k)
是n中k个元素的组合数。
我不认为(不确定)在最坏的情况下你可以做得更好,因为在最坏的情况下似乎很难不枚举所有可能的子串(最后一个要评估的可能是唯一一个)没有冗余...)。也许平均而言你可以做得更好......
答案 1 :(得分:0)
您可以使用对最长公共子序列算法的修改。在这种情况下,您正在寻找最短的唯一子序列。下面显示的是动态编程解决方案的一部分,它比递归解决方案更有效。最长公共子序列算法的修改在下面的注释中描述:
"Information" conflicts with "Steven": 988 is a prefix of 98816740
然后,您可以将此代码放入函数中,并为集合中的每个字符串调用此函数,以查找集合中最短唯一子序列的长度。
一旦获得最短唯一子序列的长度,就可以回溯打印子序列。
答案 2 :(得分:-1)
您应该使用修改后的Trie结构,以下列方式将字符串插入到trie中:
Foo-bar-on
-t
bar-stool
-foo
其余的很简单,只需选择正确的压缩节点[0] char
那Radix tree应该有帮助