从其子序列的集合中构建最短的字符串

时间:2014-01-14 06:47:00

标签: string algorithm

给出一个字符串的子序列集合。

例如:

abc
acd
bcd

问题是,如何从这些序列中确定最短的字符串?

对于上面的示例,最短的字符串是abcd

此处子序列表示字符串的一部分,但不一定是连续的。像acd一样是字符串abcd的子序列。

编辑:这个问题实际上来自Project Euler problem 79,在那个问题中,我们有50个子序列,每个子序列的长度为3.所有字符都是数字。

5 个答案:

答案 0 :(得分:5)

这个问题得到了很好的研究,并创造了“Shortest common supersequence

对于两个字符串,它在O(n)中。假设n是字符串的最大长度。 O(n)用于构建 suffix array ,然后用O(n)来解决Longest Common Subsequence问题。

对于两个以上的字符串,它是NP-Complete。

答案 1 :(得分:3)

复杂性

在一般情况下,如上所述,这个问题将是NP难的。有一种方法可以解决具有后缀结构的问题,但您也可以使用有向图来执行此操作。我不能肯定地说在某种意义上它是否更好 - 但在困难的角落案件中可能会有一些优势。

图表解决方案

要了解如何使用图表 - 您只需要正确构建它。设字符串的字母是顶点,字母的顺序将定义边。这意味着,ab将表示顶点ab以及ab之间的连接。当然,连接是有针对性的(即如果ab相关联,那并不意味着ba相关联,所以aba --> b

在这些定义之后,您将能够构建所有图形。对于你的样本:

  

Simple regular case

- 足够简单。但是abcd也可以用两个长度为ab, ac, ad, bc, bd, cd的字符串表示 - 所以我也会为此显示图表(它只是为了更清晰):

  

Complex regular case

然后,要找到您的解决方案,您需要在此图表中find a path with maximal length。显然,NP的硬度来源于#34;。从上述两种情况来看,如果我们从4顶点开始并遍历图形直到找到a路径,则最大长度为a->b->c->d

转角案例

非唯一解决方案:实际上,您可能会遇到无法严格定义超集的字符串集。示例:ab, ad, bd, ac, cdabcdacbd都适合这些子字符串。但是,实际上,这不是太糟糕的问题。看图:

  

Ambiguous way case

(我已经选择了原因:它就像第二张图,但没有一个连接,这就是为什么结果不明确)。最大路径长度现在为3 - 但可以使用两个路径:abdacd来覆盖。那么如何恢复至少一种解决方案呢?简单:因为结果字符串将具有相同的长度(来自我们已经找到它们的方式的定义) - 我们可以从第一个字符串的开头走,并检查第二个字符串中的符号。如果他们匹配,那么它就是一个严格的符号位置。但如果他们不 - 那么我们可以自由选择当前符号之间的任何顺序。那将是:

  • [a] matches [a],因此当前结果为a
  • [b]不匹配[c],因此我们可以放置bccb。让它成为第一。然后结果为abc
  • [d]匹配[d],因此当前结果为abc + d,即abcd

这是"合并"我们可以自由选择任何结果。但是,这有点扭曲,因为现在我们无法使用任何找到的路径 - 我们应该找到所有路径的最大长度(否则我们将无法恢复完全超级序列)

接下来,不存在的解决方案:可能存在某些字符串中的符号顺序无法用于重现超序的情况。显然,这意味着一个订单违反了其他订单,因此,将有两个字符串,其中两个符号具有不同的顺序。同样,最简单的情况:abc, cbd。在图表上:

  

Non-existent solution

- 即将到来的结果将是图形循环 - 它可能不那么简单(如上图所示) - 但它总是在订单被打破的情况下。因此,您需要意识到的是找到graph cycle。事实上。这不是你必须单独做的事情。您只需在图表最长路径搜索中添加周期检测。

第三:重复符号:这是最棘手的案例。如果字符串包含重复的符号,那么图形创建会更复杂,但仍然可以完成。例如,我们有三个条件:aac, abc, bbc。解决方法是aabbc。如何构建图表?现在我们不能只添加链接(至少因为循环)。但我建议采取以下方式:

  • 让我们处理所有字符串,为符号分配索引。每个字符串重置索引。如果符号仅出现一次,则索引将为1。对于我们的字符串,意思是:a 1 a 2 c 1 1 b 1 c 1 和b 1 b 2 c 1 。之后,为我们找到的每个符号存储最大索引。对于上面的示例,2a2b1c
  • 如果两个连接的索引符号具有相同的原始符号,则连接完成"按原样#34;。例如, 1 a 2 将只生成一个从 1 2 的连接
  • 如果两个连接的索引符号具有不同的原始符号,则任何第一个索引符号可以连接到任何第二个索引符号。例如,b 1 c 1 将导致(b 1 到c 1 )连接和(b < sub> 2 到c 1 )连接。我们如何知道索引符号的数量?我们已经完成了第一步(即找到最大索引)

因此,上面示例的图表将如下所示:

          +------------+
          |            |
          |            |
 +------>[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个数字,09都在开头,然后您有2个选项。然后你尝试两者并获得90是最佳解决方案。

更一般地说,您可以使用深度优先搜索算法。诀窍是当你发现只有一个角色出现在开头时,只需选择它,它就会 最佳解决方案的途径。

答案 3 :(得分:1)

我认为我们可以从图表开始  我不确定是否正确,但是如果我们使用a-> b建立图表,如果b在a之后,所有路径的长度为1。 现在,我们必须找到最长的距离(DFS可以帮助) 我将尝试提供示例。

说字符串是:

  

ABC
  ACD
  BCD
  BCE

我们形成一个图表:
enter image description here
现在剩下的主要事情是组合节点e和d,因为所需的字符串可以是abcdeabced

这是我不知道该怎么办,所以也许有人可以提供帮助!

很抱歉发布此答案,评论不能包含图片。

答案 4 :(得分:1)

从子序列中构造图形,然后使用DFS在O(E)中找到图形的拓扑排序,以获得所需的最短长度的字符串,其中包含所有子序列。但正如您所注意到的那样,如果图形具有循环,那么拓扑排序是无效的,那么循环中的字符需要重复,这很难解决。

结论: - 如果图表中没有周期并且在O(E)中解决它就会很幸运,否则就会变得不走运并最终做蛮力。