题目
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
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:
整个过程可以分成两个部分:先通过BFS从start找到end,在找的过程中需要记录前驱单词,再用DFS反向找回完整路径。
但是用Java实现上述过程会遇到TLE。为了能让用时尽可能短,有如下几点需要注意的地方:
1. 由于最后生成路径的时候,需要从end找到start构造ArrayList,即使用LinkList来协助构造,性能也不好。解决办法:不从start找end了,反过来从end找start,找到后,再从start往end构造路径,性能会有明显提升。
2. 在BFS过程中,需要替换String的每一位字符,先转换成char数组再操作,性能也会有明显提升。
3. 在BFS过程中,注意避免一些不必要的搜索,具体细节参考如下代码。
最终在LeetCode测试中,Java实现达到了800ms用时。
此外,双向BFS也可以用来提升性能,而且效果会十分显著,这里没有具体实现。
代码
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; public class WordLadderII { class WordWithLevel { String word; int level; public WordWithLevel(String word, int level) { this.word = word; this.level = level; } } private String end; private ArrayList<ArrayList<String>> result; private Map<String, List<String>> nextMap; public ArrayList<ArrayList<String>> findLadders(String start, String end, HashSet<String> dict) { result = new ArrayList<ArrayList<String>>(); this.end = end; // unvisited words set Set<String> unVisited = new HashSet<String>(); unVisited.addAll(dict); unVisited.add(start); unVisited.remove(end); // used to record the map info of <word : the words of next level> nextMap = new HashMap<String, List<String>>(); for (String e : unVisited) { nextMap.put(e, new ArrayList<String>()); } // BFS to search from the end to start Queue<WordWithLevel> queue = new LinkedList<WordWithLevel>(); queue.add(new WordWithLevel(end, 0)); boolean found = false; int finalLevel = Integer.MAX_VALUE; int currentLevel = 0; int preLevel = 0; Set<String> visitedWordsInThisLevel = new HashSet<String>(); while (!queue.isEmpty()) { WordWithLevel wordWithLevel = queue.poll(); String word = wordWithLevel.word; currentLevel = wordWithLevel.level; if (found && currentLevel > finalLevel) { break; } if (currentLevel > preLevel) { unVisited.removeAll(visitedWordsInThisLevel); } preLevel = currentLevel; char[] wordCharArray = word.toCharArray(); for (int i = 0; i < word.length(); ++i) { char originalChar = wordCharArray[i]; boolean foundInThisCycle = false; for (char c = ‘a‘; c <= ‘z‘; ++c) { wordCharArray[i] = c; String newWord = new String(wordCharArray); if (c != originalChar && unVisited.contains(newWord)) { nextMap.get(newWord).add(word); if (newWord.equals(start)) { found = true; finalLevel = currentLevel; foundInThisCycle = true; break; } if (visitedWordsInThisLevel.add(newWord)) { queue.add(new WordWithLevel(newWord, currentLevel + 1)); } } } if (foundInThisCycle) { break; } wordCharArray[i] = originalChar; } } if (found) { // dfs to get the paths ArrayList<String> list = new ArrayList<String>(); list.add(start); getPaths(start, list, finalLevel + 1); } return result; } private void getPaths(String currentWord, ArrayList<String> list, int level) { if (currentWord.equals(end)) { result.add(new ArrayList<String>(list)); } else if (level > 0) { List<String> parentsSet = nextMap.get(currentWord); for (String parent : parentsSet) { list.add(parent); getPaths(parent, list, level - 1); list.remove(list.size() - 1); } } } }
原文:http://blog.csdn.net/perfect8886/article/details/19645691