字梯问题
给定两个单词(start, end)和一个字典,要求找出从单词start变化到end的最小序列。变化过程中出现的中间单词必须是字典中有的单词,且每次只能是变化其中的一个字母。
比如start= “hit”, end= “cog”, dict = [“hot”, “dot”, “dog”, “lot”, “log”]。 那么从start变化到end经过了5步,即"hit"→"hot" →"dot" →"dog"→"cog"。
# _*_ coding=utf-8 _*_
__author__ = 'SRF'
__date__ = '2019/5/26 8:05'
# 字梯问题
'''
将单词和与其相差一个字符的单词之间构造边 构造无向图
利用宽搜计算两点间最短路径
'''
from collections import defaultdict
class BFSResult:
def __init__(self):
self.level = {}
self.parent = {}
# 最短路径
def find_shortest_path(r, v):
path = [v, ]
# 获得源点
source_vertex = [vertex for vertex, level in r.level.items() if level == 0][0]
if v != source_vertex:
while r.parent[v] != source_vertex and r.parent[v] is not None:
v = r.parent[v]
path.append(v)
path.append(source_vertex)
path.reverse()
return path
class Graph():
def __init__(self):
self.adj = defaultdict(list)
def add_edge(self, u, v):
for w in v:
if w in self.adj[u] or len(w) != len(u):
continue
match = [i for i in range(len(u)) if w[i] == u[i]] # 存储相同字符的索引
if len(match) == len(u) - 1: # 若相同字符为字符串长度减一 符合变化要求 构造边
self.adj[u].append(w)
self.adj[w].append(u)
def bfs(g, s): # 图 初始节点
r = BFSResult()
r.level = {s: 0}
r.parent = {s: None}
i = 1 # 记录层编号 012
frontier = [s]
while frontier:
next = []
for u in frontier:
for v in g.adj[u]:
if v not in r.level:
r.level[v] = i
r.parent[v] = u
next.append(v)
frontier = next
i += 1
return r
if __name__ == '__main__':
g = Graph()
dict = ["hot", "dot", "dog", "lot", "log"]
start = "hit"
end = "cog"
dict.extend([start, end]) # 将起始点加入dict 否则构造的图不完整
for i in dict:
g.add_edge(i, dict)
r = bfs(g, start)
print(start + "到" + end + "的最短路径为")
print(find_shortest_path(r, end))