今天这篇笔记讲讲一直都弄得不是很清楚的回溯算法。回溯写法用于dfs比较常见,由于深度优先,如果搜完之后还需要继续搜索,那么就只好往前回溯了。深度优先之所以需要这样遍历,是为了不重复搜索,特别是这种树形结构的。在形式上比较像bfs,但实质上是dfs,因为一定是在一个搜索路径下走完,才来寻找其他的路径。
这一题下面这种解法确实有一些难度,先是用bfs来建立树,并且利用层次进行标明,然后再利用dfs反向搜索路径(反向搜索路径,是因为如果正向的话发散太多不好记录,反向因为最终都会归于根节点,这是根据建树时的性质决定的。
然而下面这种解法依然 TLE
public class Solution {
class Node {
String word;
int level;
public Node(String word, int level) {
this.word = word;
this.level = level;
}
}
private String end;
private List<List<String>> res;
private Map<String, List<String>> maps;
public List<List<String>> findLadders(String start, String end,
List<String> dict) {
res = new ArrayList<>();
// unvisited words set
dict.add(end);
dict.remove(start);
// used to record the map info of <word : the words of next level>
maps = new HashMap<>();
for (String e : dict) {
maps.put(e, new ArrayList<>());
}
// BFS to search from the end to start
Queue<Node> queue = new LinkedList<Node>();
queue.add(new Node(start, 0));
boolean found = false;
int finalLevel = Integer.MAX_VALUE;
int currentLevel = 0;
Set<String> visitedWordsInThisLevel = new HashSet<>();
while (!queue.isEmpty()) {
Node node = queue.poll();
String word = node.word;
int level = node.level;
if (level >= finalLevel) {
break;
}
if (level > currentLevel) {
dict.removeAll(visitedWordsInThisLevel);
visitedWordsInThisLevel.clear();
}
currentLevel = level;
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; // change to another word
String newWord = new String(wordCharArray);
if (c != originalChar && dict.contains(newWord)) {
maps.get(newWord).add(word);
if (newWord.equals(end)) {
found = true;
finalLevel = currentLevel + 1;
foundInThisCycle = true;
break;
}
if (visitedWordsInThisLevel.add(newWord)) {
queue.add(new Node(newWord, currentLevel + 1));
}
}
}
if (foundInThisCycle) {
break; // break in two cycle
}
wordCharArray[i] = originalChar;
}
}
if(found){
List<String> tmplist = new LinkedList<>();
generatePath(end,start,tmplist);
}
return res;
}
private void generatePath(String start, String end, List<String> list){
if(start.equals(end)){
List<String> tmplist = new LinkedList<>(list);
tmplist.add(end);
Collections.reverse(tmplist);
res.add(tmplist);
return;
}
list.add(start);
List<String> tmplist = maps.get(start);
for(String e:tmplist)
generatePath(e,end,list);
list.remove(list.size()-1);
}
}