126. Word Ladder II
给一个开始单词和一个结尾单词和一个字符串数组,使用数组中的作为候选字符串,每次只改变字符串的一个字符,直到从开始单词转变为结尾单词,找出所有最短的转化单词的路径。
Input:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
Output:
[ [“hit”,“hot”,“dot”,“dog”,“cog”],
[“hit”,“hot”,“lot”,“log”,“cog”] ]
有几个点:
- 使用Arrays.asList声明的列表长度是不可改变的,只能修改其中的元素,而不能增加或删减
- 最大的区别是构想的这个图的结点不是每个字符串,而是遍历的路径,这样找到endWord时就可以把当前路径加入到解集中了
- 但是!因为要找出所有的路径,所有还需要一个标记记录当前bfs遍历的层次,当找到第一个解时就记住这个层次minLevel,然后继续遍历
- 直到遍历的层次大于minLevel时,遍历停止,此时解集中包含所有的最短路径
- 但是我这个算法超时了fxxk,需要优化优化
List<List<String>> res = new ArrayList<>();
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<String> visitedString = new ArrayList<>();
visitedString.add(beginWord);
List<String> allWords = new ArrayList<>(wordList);
//将queue看作是一个路径的dfs图
Queue<List<String>> queue = new LinkedList<>();
List<String> first = new ArrayList<>();
first.add(beginWord);
queue.add(first);
int level = 1;
int minLevel = Integer.MAX_VALUE;
while (!queue.isEmpty()) {
List<String> words = queue.peek();
queue.poll();
if (words.size() > level) {
//去掉该层所有已经访问过的结点
for (String s : visitedString)
allWords.remove(s);
visitedString.clear();
if (words.size() > minLevel)
break;
else {
level = words.size();
}
}
//遍历该层中所有的结点,对每个结点获得其所有临近结点,加入到该结点的边上
String last = words.get(words.size()-1);
for (int j = 0; j < last.length(); j++) {
StringBuffer news = new StringBuffer(last);
// System.out.println(allWords + ", " + news);
for (char ch = 'a'; ch <= 'z'; ch++) {
news.setCharAt(j, ch);
if (allWords.contains(news.toString())) {
List<String> newwords = new ArrayList<>(words);
newwords.add(news.toString());
if (news.toString().equals(endWord)) {
minLevel = level;
res.add(new ArrayList<>(newwords));
} else {
queue.add(newwords);
visitedString.add(news.toString());
}
}
}
}
}
return res;
}
127. Word Ladder
和上题基本一样,只是要求返回最短的路径的个数。
Input:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
Output: 5
Explanation: As one shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
return its length 5.
比上题简单一些,因为不用记录列表,而且dfs只要找到符合要求的解就可以判断这个最短路径,直接返回就行了:
- 使用一个visited数组标记所有访问过的元素
- 将和每个字符串只有一个字符差别的字符串作为该字符串的相邻结点加入到队列中
- 直到找到endWord,此时就是最短的路径
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
boolean[] visited = new boolean[wordList.size()];
Queue<String> queue = new LinkedList<>();
queue.add(beginWord);
int len = 1;
while (!queue.isEmpty()) {
int n = queue.size();
for (int i = 0; i < n; i++) {
String cur = queue.peek();
if (cur.equals(endWord))
return len;
queue.poll();
for (int j = 0; j < wordList.size(); j++) {
if (visited[j]) continue;
if (onlyOneDiff(cur, wordList.get(j))) {
visited[j] = true;
queue.add(wordList.get(j));
}
}
}
len++;
}
return 0;
}
public boolean onlyOneDiff(String a, String b) {
int diff = 0;
for (int i = 0; i < a.length(); i++) {
if (a.charAt(i) != b.charAt(i))
diff++;
}
return diff<=1;
}