给出一个字符串的子序列集合。
例如:
abc
acd
bcd
问题是,如何从这些序列中确定最短的字符串?
对于上面的示例,最短的字符串是abcd
。
此处子序列表示字符串的一部分,但不一定是连续的。像acd
一样是字符串abcd
的子序列。
编辑:这个问题实际上来自Project Euler problem 79,在那个问题中,我们有50个子序列,每个子序列的长度为3.所有字符都是数字。
答案 0 :(得分:5)
这个问题得到了很好的研究,并创造了“Shortest common supersequence”
对于两个字符串,它在O(n)中。假设n是字符串的最大长度。 O(n)用于构建 suffix array ,然后用O(n)来解决Longest Common Subsequence问题。
对于两个以上的字符串,它是NP-Complete。
答案 1 :(得分:3)
在一般情况下,如上所述,这个问题将是NP难的。有一种方法可以解决具有后缀结构的问题,但您也可以使用有向图来执行此操作。我不能肯定地说在某种意义上它是否更好 - 但在困难的角落案件中可能会有一些优势。
要了解如何使用图表 - 您只需要正确构建它。设字符串的字母是顶点,字母的顺序将定义边。这意味着,ab
将表示顶点a
和b
以及a
和b
之间的连接。当然,连接是有针对性的(即如果a
与b
相关联,那并不意味着b
与a
相关联,所以ab
是a --> b
)
在这些定义之后,您将能够构建所有图形。对于你的样本:
- 足够简单。但是abcd
也可以用两个长度为ab, ac, ad, bc, bd, cd
的字符串表示 - 所以我也会为此显示图表(它只是为了更清晰):
然后,要找到您的解决方案,您需要在此图表中find a path with maximal length。显然,NP的硬度来源于#34;。从上述两种情况来看,如果我们从4
顶点开始并遍历图形直到找到a
路径,则最大长度为a->b->c->d
。
非唯一解决方案:实际上,您可能会遇到无法严格定义超集的字符串集。示例:ab, ad, bd, ac, cd
。 abcd
和acbd
都适合这些子字符串。但是,实际上,这不是太糟糕的问题。看图:
(我已经选择了原因:它就像第二张图,但没有一个连接,这就是为什么结果不明确)。最大路径长度现在为3
- 但可以使用两个路径:abd
和acd
来覆盖。那么如何恢复至少一种解决方案呢?简单:因为结果字符串将具有相同的长度(来自我们已经找到它们的方式的定义) - 我们可以从第一个字符串的开头走,并检查第二个字符串中的符号。如果他们匹配,那么它就是一个严格的符号位置。但如果他们不 - 那么我们可以自由选择当前符号之间的任何顺序。那将是:
[a] matches [a]
,因此当前结果为a
[b]
不匹配[c]
,因此我们可以放置bc
或cb
。让它成为第一。然后结果为abc
[d]
匹配[d]
,因此当前结果为abc
+ d
,即abcd
这是"合并"我们可以自由选择任何结果。但是,这有点扭曲,因为现在我们无法使用任何找到的路径 - 我们应该找到所有路径的最大长度(否则我们将无法恢复完全超级序列)
接下来,不存在的解决方案:可能存在某些字符串中的符号顺序无法用于重现超序的情况。显然,这意味着一个订单违反了其他订单,因此,将有两个字符串,其中两个符号具有不同的顺序。同样,最简单的情况:abc, cbd
。在图表上:
- 即将到来的结果将是图形循环 - 它可能不那么简单(如上图所示) - 但它总是在订单被打破的情况下。因此,您需要意识到的是找到graph cycle。事实上。这不是你必须单独做的事情。您只需在图表最长路径搜索中添加周期检测。
第三:重复符号:这是最棘手的案例。如果字符串包含重复的符号,那么图形创建会更复杂,但仍然可以完成。例如,我们有三个条件:aac, abc, bbc
。解决方法是aabbc
。如何构建图表?现在我们不能只添加链接(至少因为循环)。但我建议采取以下方式:
1
。对于我们的字符串,意思是:a 1 a 2 c 1 , 1 b 1 c 1 和b 1 b 2 c 1 。之后,为我们找到的每个符号存储最大索引。对于上面的示例,2
为a
,2
为b
,1
为c
因此,上面示例的图表将如下所示:
+------------+ | | | | +------>[a2]------+ | | | | | | V V | [a1]---->[c1]<----[b2] | | ^ ^ | | | | | +------>[b1]------+ | ^ | | | +------------+
- 对于路径a 1 a 2 b 2 b 5 > 1 c 1 和 1 a 2 b 1 b 2 子> C <子> 1 子>。我们可以选择其中任何一个,忽略结果字符串aabbc
中的索引。
答案 2 :(得分:2)
也许没有通用的高效算法这种问题。但这是针对这一特定问题的解决方案projecteuler 79。您想观察输入文件。您会发现7
仅出现在所有序列的开头,因此7
应放在开头。然后你会发现数字3
是开头唯一的字符,然后你将3
放在第二个位置。等等,您可以获得73162890
。特殊情况是最后2
个数字,0
和9
都在开头,然后您有2
个选项。然后你尝试两者并获得90
是最佳解决方案。
更一般地说,您可以使用深度优先搜索算法。诀窍是当你发现只有一个角色出现在开头时,只需选择它,它就会 最佳解决方案的途径。
答案 3 :(得分:1)
我认为我们可以从图表开始 我不确定是否正确,但是如果我们使用a-> b建立图表,如果b在a之后,所有路径的长度为1。 现在,我们必须找到最长的距离(DFS可以帮助) 我将尝试提供示例。
说字符串是:
ABC
ACD
BCD
BCE
我们形成一个图表:
现在剩下的主要事情是组合节点e和d,因为所需的字符串可以是abcde
或abced
。
这是我不知道该怎么办,所以也许有人可以提供帮助!
很抱歉发布此答案,评论不能包含图片。
答案 4 :(得分:1)
从子序列中构造图形,然后使用DFS在O(E)中找到图形的拓扑排序,以获得所需的最短长度的字符串,其中包含所有子序列。但正如您所注意到的那样,如果图形具有循环,那么拓扑排序是无效的,那么循环中的字符需要重复,这很难解决。
结论: - 如果图表中没有周期并且在O(E)中解决它就会很幸运,否则就会变得不走运并最终做蛮力。