单词接龙 II (来自lintecode:https://www.lintcode.com/problem/word-ladder-ii/?_from=ladder&&fromId=1)

给出两个单词(startend)和一个字典,找出所有从startend的最短转换序列。

变换规则如下:

1.每次只能改变一个字母。

2.变换过程中的中间单词必须在字典中出现。

样例

给出数据如下:

start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

返回

[
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
]

注意事项

1.所有单词具有相同的长度。

2.所有单词都只包含小写字母。


 

构造代码前的思路:

1.首先构造有向图,将start, end 以及dict里所有字符的可变化对象列在一个字典里。

2.计算每个字符距离终点的距离(BFS)

3.根据距离逐一添加进result (DFS)

 


操作实现:
 
import copy
class Solution:
    graph = {}
    used = set()
    result = []
    def findLadders(self, start, end, dict):
        self.graph[start] = set()
        self.graph[end] = set()
        for word in dict:
            self.graph[word] = set()#先建立起空的有向图
        self.buildgraph(start, dict)
        self.buildgraph(end, dict)
        for word in dict:
            self.buildgraph(word, dict)#开始建立有向图
        dist = self.distance(end)#开始建立距离表
        self.findresult(start, end, dist, [])#根据距离建立result
        return self.result
        
    def buildgraph(self, word, dict):#建立有向图
        for char in range(len(word)):
            left = word[:char]
            right = word[char + 1:]
            for mid in "abcdefghijklmnopwrstuvwxyz":
                neword = left + mid + right
                if neword != word and neword in dict:
                    self.graph[neword].add(word)#存在多个出度,所以是append而不是赋值等号
                    self.graph[word].add(neword)
    def distance(self, word):
        dist = {}
        dist[word] = 0
        self.used.add(word)#由于该有向图存在环,可以互相变化,为了避难重复使用导致覆盖距离
        temp_list = [word]#为了BFS建立一个临时的表格
        while temp_list:
            word = temp_list.pop(0)#从最左开始取值,保证距离是从小到大
            for neighbor in self.graph[word]:
                if neighbor not in self.used:
                    self.used.add(neighbor)
                    temp_list.append(neighbor)
                    dist[neighbor] = dist[word] + 1
        return dist
    def findresult(self, word, end, dist, path):
        path.append(word)
        if word == end:
            self.result.append(copy.deepcopy(path))
            return
        for neighbor in self.graph[word]:
            if dist[neighbor] == dist[word] - 1: #如果距离相差为1,则录用
                self.findresult(neighbor, end, dist, path)
                path.pop()