中间强制单词的单词阶梯问题

Cha*_*t1c 2 python algorithm graph dijkstra shortest-path

我正在研究一个关于单词阶梯的问题,带有一些额外的约束(给出了单词列表,并且阶梯仅由这些单词构建,而不是整个英语)。\n除了传统的Word Ladder问题:

\n
\n
    \n
  1. 最小化单词阶梯的字母距离。
  2. \n
\n
\n

例如,“aab”和“aaa”的距离为 1,因为“b”是字母表中的第二个字母,而“a”是第一个字母。“bbb”和“bwb”的距离为 21,因为“b”是字母表中的第二个字母,而“w”是第二十三个字母。

\n
\n
    \n
  1. 我们需要在梯子中使用一组特定单词中的一个,例如“绕行”。
  2. \n
\n
\n

这意味着,给定原始单词的单词列表 (>= 1),这些单词中至少有一个必须出现在单词梯中。

\n

该问题有一个复杂度约束,即 O(Elog(W) + Wlog(W))),其中

\n
\n

E是仅相差一个字母的单词对的数量

\n

W是单词总数

\n
\n

请注意,这种复杂性不涉及任何与“绕行”字的大小相关的术语。

\n
# One example is (we denote the word as indices in the list):\nwords = [\xe2\x80\x99aaa\xe2\x80\x99,\xe2\x80\x99bbb\xe2\x80\x99,\xe2\x80\x99bab\xe2\x80\x99,\xe2\x80\x99aaf\xe2\x80\x99,\xe2\x80\x99aaz\xe2\x80\x99,\xe2\x80\x99baz\xe2\x80\x99,\xe2\x80\x99caa\xe2\x80\x99,\xe2\x80\x99cac\xe2\x80\x99,\xe2\x80\x99dac\xe2\x80\x99,\xe2\x80\x99dad\xe2\x80\x99,\xe2\x80\x99ead\xe2\x80\x99,\xe2\x80\x99eae\xe2\x80\x99,\xe2\x80\x99bae\xe2\x80\x99,\xe2\x80\x99abf\xe2\x80\x99,\xe2\x80\x99bbf\xe2\x80\x99]\nstart word = 0         # ("aaa")\nend word = 1           # ("bbb")\ndetour = [12]          # ("bae")\n# The result path is: [0, 6, 7, 8, 9, 10, 11, 12, 2, 1]\n# corresponding to the list of the words: [\xe2\x80\x99aaa\xe2\x80\x99, \xe2\x80\x99caa\xe2\x80\x99, \xe2\x80\x99cac\xe2\x80\x99, \xe2\x80\x99dac\xe2\x80\x99, \xe2\x80\x99dad\xe2\x80\x99, \xe2\x80\x99ead\xe2\x80\x99, \xe2\x80\x99eae\xe2\x80\x99, \xe2\x80\x99bae\xe2\x80\x99, \xe2\x80\x99bab\xe2\x80\x99, \xe2\x80\x99bbb\xe2\x80\x99]\n
Run Code Online (Sandbox Code Playgroud)\n

现在我的实现只是运行Dijkstra\xe2\x80\x99s 算法,其复杂度为 O(Elog(W)),对从起始词到“绕行”词之一,以及从绕行词到最终目标词。计算所有并找到字母距离最小的一个。

\n

我认为这不好,我不确定它是否超出了时间复杂度。同时,我不明白为什么复杂性不涉及“绕道”词的大小。如何确保路径最短,同时至少包含一个“绕道”词(并满足复杂度)?

\n

有没有人有更好的主意来解决这个问题?\n非常感谢。

\n

kcs*_*red 5

这可以通过使用小幅增强以与 Dijkstra 算法完全相同的时间复杂度来完成。我们用两个顶点和替换v原始图中的每个顶点,表示我们是否已经访问了绕道。我们现在正在搜索从到 的最短路径,其中 x 分别是或如果 start 是或不是绕道。(v, 0)(v, 1)(start, x)(end, 1)10

\n

优先级队列仅在优先级/距离为 时Q初始化。Dijkstra 算法中邻居的主循环转换成这样(伪代码):(start, x)0

\n
while Q is not empty:\n    (v, has_detour) <- extract_min_heap(Q)\n\n    for neighbor, edge_cost in neighbors[v]:\n        detour_status <- has_detour | is_detour(neighbor)\n        alt_cost = dist[v, has_detour] + edge_cost\n\n        if alt_cost < dist[neigh, detour_status]:\n            dist[neigh, detour_status] = alt_cost\n            predecessor[neigh, detour_status] = (v, has_detour)\n            add (neigh, detour_status) to Q with priority == alt_cost\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,我们没有通过原始边集显式构造增强图 G*,仅通过 Dijkstra 的辅助数据结构隐式构造。当然,您实际上可以存储新图,其定义如下:

\n
Given a directed graph G = (V, E),\nDefine a new directed graph G* = (V*, E*):\n\nVertex set V* := V x {0,1}\n\nEdge set E* := {((v,1), (w,1)) | (v,w) \xe2\x88\x88 E} \n             \xe2\x88\xaa {((v,0), (w,0)) | (v,w) \xe2\x88\x88 E and w \xe2\x88\x89 detours} \n             \xe2\x88\xaa {((v,0), (w,1)) | (v,w) \xe2\x88\x88 E and w \xe2\x88\x88 detours}\n
Run Code Online (Sandbox Code Playgroud)\n

由于我们的新图(我们实际运行 Dijkstra 的图)具有2|V|顶点和2|E|边,因此新的渐近运行时和空间复杂度与 Dijkstra 的原始实现中的相同。确保使用set基于 hashmap 的数据结构来is_detour()实现O(1)

\n
\n

有关完整的 Python 实现,请参阅下文。与弯路相关的代码更改几乎都在该主循环中:大部分代码正在构建标准字梯图。构建图表可以采用|V|^2 * word_len|V|*(word_len^2) + |E|,具体取决于您的操作方式。我在这里选择了第二种方法。

\n
Given a directed graph G = (V, E),\nDefine a new directed graph G* = (V*, E*):\n\nVertex set V* := V x {0,1}\n\nEdge set E* := {((v,1), (w,1)) | (v,w) \xe2\x88\x88 E} \n             \xe2\x88\xaa {((v,0), (w,0)) | (v,w) \xe2\x88\x88 E and w \xe2\x88\x89 detours} \n             \xe2\x88\xaa {((v,0), (w,1)) | (v,w) \xe2\x88\x88 E and w \xe2\x88\x88 detours}\n
Run Code Online (Sandbox Code Playgroud)\n

根据您的输入,可以像这样使用:

\n
words = [\'aaa\', \'bbb\', \'bab\', \'aaf\', \'aaz\', \'baz\', \'caa\', \'cac\', \'dac\', \'dad\', \'ead\', \'eae\', \'bae\', \'abf\', \'bbf\']\nstart = 0\nend = 1\ndetours = [12]\n\nprint(word_ladder(words=words, start_word_idx=start,\n                  end_word_idx=end, detour_idxs=detours))\n
Run Code Online (Sandbox Code Playgroud)\n
[0, 6, 7, 8, 9, 10, 11, 12, 2, 1]\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,Dijkstra 的此实现不使用 Decrease-Key,因此理论上的运行时间不是最优的。当然,大多数实际实现也是如此;如果您担心的话,请随意使用斐波那契堆或类似的方法。

\n