所以我在这里有问题。我得到了一组随机单词,我的工作是找出是否存在至少一个单词序列将所有单词(第一个字母)排成一行。
例如单词序列(苹果-鹰-大象-老虎)将返回true。但是单词序列(苹果-鹰-大象-桃子)将返回false。
所以我想使用一些图论。我发现可以创建有向图,并对其进行暴力破解以找到图中的最长路径或汉密尔顿路径。这里的问题是图可以是循环的,因此问题始终是NP已满。它确实是最好的解决方案,还是我错过了什么,而实际上问题要容易得多?
最好最好是有一个无环图,所以我可以使用关键路径算法在o(n + m)中找到解决方案。
蛮力确实是我唯一的选择,还是有其他替代方法可以解决此问题?起初,我想到了一些类似先计算起尾字母然后比较它们的方法,但是它有自己的问题,我无法真正解决它们。
无论如何,如果蛮力是我唯一的选择,那么有什么好的方法可以最佳地优化最长路径算法?
答案 0 :(得分:0)
仅当存在每个单词(以单词的最后一个字符开头)(一个例外是单词的最后一个例外)时,序列才有可能。 可能的解决方案是构建一个包含每个单词的第一个和最后一个字符并检查其是否满足该属性的哈希映射,请确保在对单词进行一次处理之后将其标记,以免再次迭代。
答案 1 :(得分:0)
好的,让我试一下。首先,我假设此问题的输入类似于带有字母[a-z](小写)的有限长度字符串(单词)的有限集 S (不是多集)。我们假设| S |> = 2,并且对于 S 中的每个 w :| w |> = 2。假设我们表示一个词 w ,它属于集合 S 。此外,我们将提取给定单词 w 的第一个字符的函数表示为 f ;同样,我们将提取给定单词 w 的最后一个字符的函数表示为 l 。例如,对于 w =“ hello”, f ( w )=“ h”和 l ( w )=“ o”。我们假设在 S 中不存在两个单词 w , w',使得 f ( w )= f ( w')和 l ( w )= l ( w'),这样可以避免在相同的源目的地具有多个边(通常,这对游戏是一个公平的假设吗?)。无论如何,可以在线性时间w.r.t.时间内检查没有两个单词具有相同的首字母和尾字母,这可以在 O ( S )时间内完成。字数。
我们将集合 S 转换为有向图(有向图) G =( V , E ) 。简单来说,我们首先将 V 和 E 都设置为空集,然后为 S 中的每个单词 w 设置: V = V U { f ( w )} U { l (< em> w )}和 E = E U {( f ( w ), l ( w ))}。先前的流程以线性时间w.r.t.输入大小| S | = | E | (重要说明:字数等于边数)。
现在,这里开始变得有趣起来。要“连接”每个单词,您必须遍历一次恰好使用每个边的路径(单词是边,字母是顶点)。这不是哈密尔顿式的道路,而是欧拉式的道路!有向图包含欧拉路径存在必要的充分条件。存在性检查可以在线性时间w.r.t. | V | (原始单词集 S 中不同的首字母和尾字母)。此外,欧拉路径的推导可以在 O (| V | + | E |)中完成(在最坏的情况下| < em> E |支配| V |,因此线性关系到集合 S 中的单词数)。
解决此问题的算法。该算法基于Hierholzer's algorithm,如果您不想阅读本文,可以找到一些信息here。这是我收集/修改的算法:
//Start the existence check & initial node selection
Compute the vertices in-degrees and out-degrees.
If all vertices have the same out-degree as in-degree, then set *v*0 to any vertex of the graph.
Else If at most one vertex has out-degree - in degree = 1 & at most one vertex has in-degree - out-degree = 1, then set *v*0 to the vertex whose out-degree - in degree = 1.
Else there is no Euler path
//Use two stacks to compute the Eulerian path using Hierholzer\'s algorithm
HEAD and TAIL both stacks empty.
Push *v*0 to HEAD.
While HEAD != empty
While out-degree of top of stack vertex, *u* > 0
Let *v* be a vertex neighbor of *u* (the edge (*u*, *v*) exists in *G*).
Push *v* to HEAD. //*v* becomes new *u*
Delete edge (*u*,*v*) from *G*
Decrease the out-degree of *u*
end while.
While HEAD != empty and top vertex *u* of HEAD out-degree == 0
Pop *u* from HEAD and Push it to TAIL
end while.
end while.
The Eulerian path is found in order in TAIL
现在,您需要从TAIL
中弹出内容。应该确切地是| E | -1个元素,并且应微不足道以重建边缘。为了获得单词返回,由于没有两个单词共享相同的首字母和最后字母,因此边缘和单词之间存在一对一的对应关系。如果先前存储在哈希表中,则检索单词顺序可以在线性时间w.r.t中完成。 | E |。
好的,因此解决此问题和复杂性的步骤: 1.将 S 转换为图 G , O (| S |)。 2.验证解决方案 O (| S |)的存在。 3.得出解 O (| S |)。 4.检索单词顺序 O (| S |)。
通常,只要给出 O (| S |)中的假设,就可以解决此任务。
这是一个有趣的任务。你从哪里得到的?