如何找到一组最短的子序列,其中一组字符串的冲突最小

时间:2017-04-10 21:32:43

标签: string algorithm

我有一个像

这样的字符串列表
  • Foobar的
  • Foobaron
  • barfoo
  • 自由自在

我想找到一组最短的子序列,这些子序列对于集合中的每个字符串都是唯一的;每个子序列中的字符不需要相邻,只是它们出现在原始字符串中的顺序。对于上面的例子,那将是(沿着其他可能性)

  • Fb(正如 Foobar 所独有的;与 Foobaron 的碰撞不可避免)
  • Fn Foobaron独有,没有其他...F...n...
  • Ft Foot
  • bs barstool
  • bf barfoo
  • e footloose

是否有一种有效的方法来挖掘这些序列并最小化碰撞字符串的数量(当无法避免碰撞时,例如当字符串是其他字符串的子串时)来自给定的字符串数组?更确切地说,选择长度N,最多N个字符的子序列集是什么,每个字符用于识别具有最少数量冲突的原始字符串。

3 个答案:

答案 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应该有帮助