字梯问题 bfs python

字梯问题

给定两个单词(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))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值