题目链接
单词接龙
题目描述
注意点
- 1 <= beginWord.length <= 10
- endWord.length == beginWord.length
- wordList[i].length == beginWord.length
- beginWord、endWord 和 wordList[i] 由小写英文字母组成
- wordList 中的所有字符串 互不相同
解答思路
- 从beginWord开始,广度优先遍历wordList,遍历i次相当于beginWord修改了i个字符,直到找到endWord为止,此时遍历了i次就是从 beginWord 到 endWord 的 最短转换序列 中的 单词数目
- 在进行广度优先遍历时,可以对单词中的每个字符进行变换,每个字符可以变换为’a’~'z’中的任意一个,如果变换后的字符串在wordList中,则其可以作为下一次广度优先遍历的起始字符串
代码
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
// 去重
Set<String> wordSet = new HashSet<>(wordList);
wordList.remove(beginWord);
if (wordSet.isEmpty() || !wordSet.contains(endWord)) {
return 0;
}
int res = 1;
// 存储变更x个字符组成且在wordSet中存在的单词
Deque<String> deque = new ArrayDeque<>();
deque.addLast(beginWord);
// 存储某个word是否被访问过
Set<String> visited = new HashSet<>();
while (!deque.isEmpty()) {
int dequeNum = deque.size();
// 遍历该层所有字符串,每一层为改变了res个字符后组成的在wordSet中存在的单词
for (int i = 0; i < dequeNum; i++) {
boolean findEndWord = changeAllCharToDeque(deque, wordSet, visited, endWord);
if (findEndWord) {
return res + 1;
}
}
res++;
}
return 0;
}
public boolean changeAllCharToDeque(Deque<String> deque, Set<String> wordSet, Set<String> visited, String endWord) {
// 遍历某个字符串的所有字符
char[] charArray = deque.pollFirst().toCharArray();
for (int j = 0; j < charArray.length; j++) {
char oldChar = charArray[j];
// 由'a'-'z'替换字符串某个位置的字符
for (char c = 'a'; c <= 'z'; c++) {
if (c == oldChar) {
continue;
}
charArray[j] = c;
String newWord = String.valueOf(charArray);
if (wordSet.contains(newWord)) {
if (newWord.equals(endWord)) {
return true;
}
if (!visited.contains(newWord)) {
deque.addLast(newWord);
visited.add(newWord);
}
}
// 还原字符串
charArray[j] = oldChar;
}
}
return false;
}
}
关键点
- 广度优先遍历的思想
- 使用队列存储广度优先遍历时每一层的单词,每一层的单词为改变了i个字符后组成的在wordSet中存在的单词
- 使用visited存储wordList中的单词是否被访问过,防止重复判断,节省时间