Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
1, Only one letter can be changed at a time
2, Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = [ "hot", "dot", "dog", "lot", "log" ]
Return
[
[ "hit", "hot", "dot", "dog", "cog" ],
[ "hit", "hot", "lot", "log", "cog" ]
]
NOTE:
All words have the same length.
All words contain only lowercase alphabetic characters.
分析:
看到单词换字母,想到的是图,一个单词每换一个字母,就生成一个相邻节点,
看到最短路径,想到BFS,BFS可以确保搜索到的一定是最短路径,
要输出最短路径,BFS之后就要从后往前原路返回,
要输出所有最短路径,则每一个节点要维护一个所有前驱节点的list,
要判断是不是前驱节点,则每一个节点要维护一个距离,
BFS的话,就要标记是否访问过,这个应该用个Hash,应为需要通过word访问node,所以应该用HashMap,
基于以上考虑,一个节点要保存所代表的word,要保存离开始节点的距离,要保存一个前驱节点的list.
感觉这个题信息量略大啊。。。
public class Solution {
class Node{
public int dist;
public String str;
public LinkedList<Node> prev;
public Node(int dist, String str){
this.dist = dist;
this.str = str;
this.prev = new LinkedList<Node>();
}
public void addPrev(Node pNode){
prev.add(pNode);
}
}
public List<List<String>> findLadders(String start, String end, Set<String> dict) {
//因为对dict里的word建立图关系,所以要把end加到字典里先
dict.add(end);
//Node可以存放更多信息,利用HashMap可以最快通过word访问到相对应的node
Map<String, Node> map = new HashMap<String, Node>();
//广度优先遍历当然用到队列
Queue<String> queue = new LinkedList<String>();
Node startNode = new Node(1, start);
queue.offer(start);
map.put(start, startNode);
List<List<String>> ret = new ArrayList<List<String>>();
//开始遍历
while(!queue.isEmpty()){
//出队当前节点
String str = queue.poll();
//找到了,开始生成路径,不需要再寻找下去
if(str.equals(end)){
getPaths(map.get(end), map, new ArrayList<String>(), ret);
return ret;
}
//尝试str变体的所有可能,每一个位置都尝试所有26个字母
for(int i=0; i<str.length(); i++){
for(int j=0; j<26; j++){
//生成新的单词
String newStr = replace(str, i, (char)('a'+j));
//如果生成的新单词不再字典里,就不再考虑了
if(dict.contains(newStr)){
//在字典里,并且没有访问过
if(!map.containsKey(newStr)){
Node node = map.get(str);
//新建节点,距离比前驱加1
Node newNode = new Node(node.dist+1, newStr);
newNode.prev = new LinkedList<Node>();
//加入前驱节点
newNode.prev.add(node);
//建立Hash关系
map.put(newStr, newNode);
//入队,参加BFS
queue.offer(newStr);
}else{
//已经访问过,则要检查能不能建立图关系
Node node = map.get(newStr);
Node prevNode = map.get(str);
//如果满足距离关系,应该加一条边,即加入前驱list
if(node.dist == prevNode.dist+1){
node.addPrev(prevNode);
}
}
}
}
}
}
return ret;
}
//替换字符生成新单词的辅助函数
private String replace(String str, int index, char c){
StringBuilder sb = new StringBuilder(str);
sb.setCharAt(index, c);
return sb.toString();
}
//根据图关系,生成路径
private void getPaths(Node end, Map<String, Node> map, ArrayList<String> curPath, List<List<String>> paths){
if(end == null){
paths.add(curPath);
return;
}
curPath.add(0, end.str);
if(!end.prev.isEmpty()){
//递归
for(Node prevNode : end.prev){
//记住每一次都要重新new一个
getPaths(prevNode, map, new ArrayList<String>(curPath), paths);
}
}else{
getPaths(null, map, curPath, paths);
}
}
}