Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
Only one letter can be changed at a time
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
Return an empty list if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the word list.
You may assume beginWord and endWord are non-empty and are not the same.
大意就是给出的beginWord根据wordList每次改变一个字母,最后变成和endWord一样,求最短的所有变形过程的记录
最开始自己的思路是只用DFS,用一个全局变量记录当前最优解长度,如果查询到更优的解,则把结果清空,重新填入,但是这样在输入wordlist超长的时候效率掺不忍睹,后来参考评论区大神,先使用BFS找最优解,再通过BFS最优解的可能路径集合作为限定通过DFS去找到所有最优解
代码如下
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
/**
* 将所有节点加入到Set集合中
*/
Set<String> allNodes = new HashSet<String>(wordList);
allNodes.add(beginWord);
/**
* 结果
*/
List<List<String>> result = new ArrayList<List<String>>();
/**
* 存储访问过的节点和该节点离起点的距离
*/
Map<String, Integer> visitedMap = new HashMap<String, Integer>();
/**
* 可达节点
*/
Map<String, List<String>> reachableNodesMap = new HashMap<String, List<String>>();
/**
* 初始化可达节点容器
*/
for(String node : allNodes){
reachableNodesMap.put(node, new ArrayList<String>());
}
/**
* bfs主要是为了填充visitedMap,这里visitedMap承担着存储所有可能是最优解的路径
*/
bfs(allNodes, reachableNodesMap, beginWord, endWord, visitedMap);
/**
* dfs为了找到指定深度的所有解,这里根据reachableNodesMap提供所有可能到达的节点并通过visitedMap筛选
* 可能最优解的路径
*/
dfs(reachableNodesMap, beginWord, endWord, visitedMap, new ArrayList<String>(), result);
return result;
}
/**
* bfs算法找寻最优解
* @param allNodes
* @param reachableNodes
* @param endWord
* @param wordList
* @param visitedMap
*/
private void bfs(Set<String> allNodes, Map<String, List<String>> reachableNodesMap, String beginWord, String endWord, Map<String, Integer> visitedMap){
Queue<String> nodeQueue = new LinkedList<String>();
nodeQueue.offer(beginWord);
visitedMap.put(beginWord, 1);
/**
* 是否找到解
*/
boolean findEnd = false;
while(!nodeQueue.isEmpty()){
int queueSize = nodeQueue.size();
for(int i = 0; i < queueSize; i++){
String currentNode = nodeQueue.poll();
List<String> reachableNodes = findReachableNodes(currentNode, allNodes);
for(String reachableNode : reachableNodes){
reachableNodesMap.get(currentNode).add(reachableNode);
if(reachableNode.equals(endWord)){
/**
* 可达节点中出现了目标节点
*/
findEnd = true;
}
if(!visitedMap.containsKey(reachableNode)){
visitedMap.put(reachableNode, visitedMap.get(currentNode) + 1);
nodeQueue.offer(reachableNode);
}
}
}
if(findEnd){
/**
* 找到解,不再往下层查找
*/
break;
}
}
}
/**
* dfs找寻给定目标下的所有解
* @param reachableValidNodes
* @param beginWord
* @param endWord
* @param visitedMap
* @param currentList
* @param result
*/
private void dfs(Map<String, List<String>> reachableNodesMap, String currentWord
, String endWord, Map<String, Integer> visitedMap, List<String> currentList
, List<List<String>> result){
currentList.add(currentWord);
if(currentWord.equals(endWord)){
//找到解
result.add(new ArrayList<String>(currentList));
}else{
List<String> reachableValidNodes = reachableNodesMap.get(currentWord);
for(String reachableValidNode : reachableValidNodes){
//当前节点的可达节点包含很多可能,我们需要用visitedMap来筛选真正的当前节点的下一层节点
if(visitedMap.get(reachableValidNode) == visitedMap.get(currentWord) + 1){
dfs(reachableNodesMap, reachableValidNode, endWord, visitedMap, currentList, result);
}
}
}
/**
* 每一次递归完成需要删除当前存储路径的最后一个节点
* 模拟dfs中到搜索到达最底端之后回到上一层节点的情况
*/
currentList.remove(currentList.size() - 1);
}
/**
* 找到给出节点所有可达节点
* @param node
* @param allNodes
* @return
*/
private List<String> findReachableNodes(String node, Set<String> allNodes){
List<String> res = new ArrayList<String>();
char chs[] = node.toCharArray();
for (char ch ='a'; ch <= 'z'; ch++) {
for (int i = 0; i < chs.length; i++) {
if (chs[i] == ch) {
continue;
}
char old_ch = chs[i];
chs[i] = ch;
if (allNodes.contains(String.valueOf(chs))) {
res.add(String.valueOf(chs));
}
chs[i] = old_ch;
}
}
return res;
}
网友评论