- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在研究一个关于单词阶梯的问题,有一些额外的限制(给出了单词列表,并且阶梯仅由这些单词构建,而不是整个英语)。除了传统的字梯问题外,还有 2 个约束:
- minimize the alphabetic distance of the word ladder.
例如,“aab”和“aaa”的距离为 1,因为“b”是字母表中的第二个字母,而“a”是第一个字母。 “bbb”和“bwb”的距离为 21,因为“b”是字母表中的第二个字母,而“w”是第二十三个字母。
- we need to use one of a set of particular words in the ladder, say "detour".
这意味着,给定原始单词的单词列表 (>= 1),这些单词中至少有一个必须出现在单词梯中。
这道题有一个复杂度约束,为 O(Elog(W) + Wlog(W))),其中
E is the number of pairs of words which differ by exactly one letter
W is the total number of words
请注意,这种复杂性不涉及任何与“绕行”字的大小相关的术语。
# One example is (we denote the word as indices in the list):
words = [’aaa’,’bbb’,’bab’,’aaf’,’aaz’,’baz’,’caa’,’cac’,’dac’,’dad’,’ead’,’eae’,’bae’,’abf’,’bbf’]
start word = 0 # ("aaa")
end word = 1 # ("bbb")
detour = [12] # ("bae")
# The result path is: [0, 6, 7, 8, 9, 10, 11, 12, 2, 1]
# corresponding to the list of the words: [’aaa’, ’caa’, ’cac’, ’dac’, ’dad’, ’ead’, ’eae’, ’bae’, ’bab’, ’bbb’]
现在我的实现只是运行 Dijkstra 算法,其复杂度为 O(Elog(W)),针对从起始词到“绕行”词之一的每个组合,以及从该绕行单词到最终目标单词。计算所有并找到字母距离最小的一个。
我认为这不好,我不确定它是否超出了时间复杂度。同时,我不明白为什么复杂性不涉及“绕道”词的大小。如何保证路径最短,同时至少包含一个“绕行”词(并满足复杂度)?
有没有人有更好的主意来解决这个问题?非常感谢。
最佳答案
这可以通过使用小幅增强以与 Dijkstra 算法完全相同的时间复杂度来完成。我们将原始图中的每个顶点 v
替换为两个顶点 (v, 0)
和 (v, 1)
,表示我们是否已经还没有走过弯路。我们现在正在搜索从 (start, x)
到 (end, 1)
的最短路径,其中 x 是 1
或 0
如果开始是或不是绕道,分别。
优先级队列Q
仅使用(start, x)
以优先级/距离0
进行初始化。 Dijkstra 算法中邻居的主循环转换为以下内容(伪代码):
while Q is not empty:
(v, has_detour) <- extract_min_heap(Q)
for neighbor, edge_cost in neighbors[v]:
detour_status <- has_detour | is_detour(neighbor)
alt_cost = dist[v, has_detour] + edge_cost
if alt_cost < dist[neigh, detour_status]:
dist[neigh, detour_status] = alt_cost
predecessor[neigh, detour_status] = (v, has_detour)
add (neigh, detour_status) to Q with priority == alt_cost
请注意,我们并没有通过原始边集显式地构造增强图 G*,而是通过 Dijkstra 的辅助数据结构隐式地构造。当然,您实际上可以存储新图,其定义如下:
Given a directed graph G = (V, E),
Define a new directed graph G* = (V*, E*):
Vertex set V* := V x {0,1}
Edge set E* := {((v,1), (w,1)) | (v,w) ∈ E}
∪ {((v,0), (w,0)) | (v,w) ∈ E and w ∉ detours}
∪ {((v,0), (w,1)) | (v,w) ∈ E and w ∈ detours}
由于我们的新图(我们实际在其上运行 Dijkstra 的)具有 2|V|
顶点和 2|E|
边,因此新的渐近运行时和空间复杂度为与 Dijkstra 最初的实现相同。确保使用 set
或基于 hashmap 的数据结构在 O(1)
中实现 is_detour()
。
有关完整的 Python 实现,请参见下文。与弯路相关的代码更改几乎都在该主循环中:大部分代码正在构建标准字梯图。构建图表可以采用 |V|^2 * word_len
或 |V|*(word_len^2) + |E|
,具体取决于您的操作方式。我在这里选择了第二种方法。
def word_ladder(words: List[str],
start_word_idx: int,
end_word_idx: int,
detour_idxs: List[int]) -> Optional[List[int]]:
"""Given a list of distinct equal length lowercase words,
find a word ladder of minimum pairwise alphabetic distance
from start to end if one exists, or return None otherwise"""
def letter_dist(letter1: str, letter2: str) -> int:
return abs(ord(letter1) - ord(letter2))
detour_idx_set = set(detour_idxs)
word_bases = collections.defaultdict(list)
graph = collections.defaultdict(list)
word_len = len(words[0])
for i, word in enumerate(words):
as_list = list(word)
for j in range(word_len):
old = as_list[j]
as_list[j] = '0'
word_base = ''.join(as_list)
for other_word_idx in word_bases[word_base]:
dist = letter_dist(old, words[other_word_idx][j])
graph[i].append((other_word_idx, dist))
graph[other_word_idx].append((i, dist))
word_bases[word_base].append(i)
as_list[j] = old
distances = collections.defaultdict(lambda: math.inf)
queue = []
start_is_detour = 1 if start_word_idx in detour_idx_set else 0
queue.append((0, start_word_idx, start_is_detour))
distances[start_word_idx, start_is_detour] = 0
parent = {}
def reconstruct_ladder() -> List[int]:
vert, detour_status = end_word_idx, 1
path = []
while (vert, detour_status) in parent:
path.append(vert)
vert, detour_status = parent[vert, detour_status]
path.append(vert)
path.reverse()
return path
while len(queue) != 0:
distance, index, has_detour = heapq.heappop(queue)
if distances[index, has_detour] != distance:
continue
for neighbor_idx, edge_cost in graph[index]:
detour_status = has_detour | (neighbor_idx in detour_idx_set)
if distance + edge_cost < distances[neighbor_idx, detour_status]:
distances[neighbor_idx, detour_status] = distance + edge_cost
parent[neighbor_idx, detour_status] = (index, has_detour)
heapq.heappush(queue,
(distances[neighbor_idx, detour_status],
neighbor_idx, detour_status))
if (end_word_idx, 1) not in parent:
return None
return reconstruct_ladder()
根据您的输入,可以这样使用:
words = ['aaa', 'bbb', 'bab', 'aaf', 'aaz', 'baz', 'caa', 'cac', 'dac', 'dad', 'ead', 'eae', 'bae', 'abf', 'bbf']
start = 0
end = 1
detours = [12]
print(word_ladder(words=words, start_word_idx=start,
end_word_idx=end, detour_idxs=detours))
[0, 6, 7, 8, 9, 10, 11, 12, 2, 1]
请注意,Dijkstra 的此实现不使用 Decrease-Key,因此理论上的运行时间不是最优的。当然,大多数实际实现也是如此。如果您担心的话,请随意使用斐波那契堆或类似的方法。
关于python - 中间强制单词的单词阶梯问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69520828/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!