題目描述
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
Only one letter can be changed at a time
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.
思路:
與上一題不同,這次需要存儲(chǔ)所有的最短路徑,就不能在入隊(duì)前把字典中的節(jié)點(diǎn)除去。我們需要一個(gè)隊(duì)列存儲(chǔ)路徑,每次取出隊(duì)列頭的路徑,把隊(duì)頭路徑的最后一個(gè)節(jié)點(diǎn)拿出來尋找下一個(gè)可達(dá)的節(jié)點(diǎn)并存入set中,如果可達(dá)節(jié)點(diǎn)為end節(jié)點(diǎn),則將路徑保存進(jìn)結(jié)果列表中,如果不為end節(jié)點(diǎn),則生成新的路徑存入隊(duì)尾。如果路徑長(zhǎng)度大于當(dāng)前路徑長(zhǎng)度(也就是層數(shù)),則更新當(dāng)前路徑長(zhǎng)度,同時(shí)將set中節(jié)點(diǎn)都從字典中清除,因?yàn)檫@些節(jié)點(diǎn)都是上層的節(jié)點(diǎn),我們不希望再走回頭路,這肯定不是最短路徑了。如果發(fā)現(xiàn)當(dāng)前路徑長(zhǎng)度已經(jīng)大于到達(dá)end節(jié)點(diǎn)的路徑長(zhǎng)度了,則后面的路徑都不是最短路徑了,直接break。
代碼:
import java.util.*;
public class Solution {
public ArrayList<ArrayList<String>> findLadders(String start, String end, HashSet<String> dict) {
ArrayList<ArrayList<String>> res = new ArrayList();
Queue<ArrayList<String>> paths = new LinkedList();
ArrayList<String> startPath = new ArrayList();
startPath.add(start);
paths.offer(startPath);
HashSet<String> nodeToMove = new HashSet();
int level = 1, lastLevel = Integer.MAX_VALUE;
while (!paths.isEmpty()){
ArrayList<String> path = paths.poll();
// 如果當(dāng)前頭部的路徑長(zhǎng)度已經(jīng)超過level,說明已經(jīng)到了下一層,之前的節(jié)點(diǎn)都可以清除了
if (path.size() > level){
// 從字典中清除節(jié)點(diǎn)
dict.removeAll(nodeToMove);
// 清除記錄的節(jié)點(diǎn)
nodeToMove.clear();
// 更新路徑長(zhǎng)度
level = path.size();
// 如果長(zhǎng)度大于到達(dá)終點(diǎn)的最短路徑,則退出循環(huán)
if (level > lastLevel) break;
}
// 拿到頭部路徑的最后一個(gè)節(jié)點(diǎn)
String last = path.get(path.size() - 1);
char str[] = last.toCharArray();
// 尋找下一個(gè)節(jié)點(diǎn)
for (int i=0; i<str.length; i++){
char original = str[i];
for (char c='a'; c<='z'; c++){
str[i] = c;
String next = new String(str);
// 如果節(jié)點(diǎn)在字典中存在
if (dict.contains(next)){
// 記錄要清除的節(jié)點(diǎn)
nodeToMove.add(next);
// 創(chuàng)建新的路徑并把下一個(gè)節(jié)點(diǎn)加入
ArrayList<String> nextPath = new ArrayList(path);
nextPath.add(next);
// 如果已經(jīng)到達(dá)終點(diǎn)則加入結(jié)果的列表中,并記錄最短路徑長(zhǎng)度
if (next.equals(end)){
res.add(nextPath);
lastLevel = level;
}
// 否則將路徑加入隊(duì)列的隊(duì)尾
else {
paths.offer(nextPath);
}
}
str[i] = original;
}
}
}
return res;
}
}