LC.P127[单词接龙]

题目描述

字典 wordList 中从单词 beginWordendWord转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk

  • 每一对相邻的单词只差一个字母。
  • 对于 1 <= i <= k 时,每个 si 都在 wordList中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWordendWord 和一个字典 wordList ,返回 从 beginWordendWord最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0

示例 1:

输入:beginWord = “hit”, endWord = “cog”, wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
输出:5
解释:一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”, 返回它的长度 5。

示例 2:

输入:beginWord = “hit”, endWord = “cog”, wordList = [“hot”,”dot”,”dog”,”lot”,”log”]
输出:0
解释:endWord “cog” 不在字典中,所以无法进行转换。

提示:

  • 1 <= beginWord.length <= 10
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 5000
  • wordList[i].length == beginWord.length
  • beginWordendWordwordList[i] 由小写英文字母组成
  • beginWord != endWord
  • wordList 中的所有字符串 互不相同

方法一:BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
if (!wordList.contains(endWord)) return 0;
Set<String> visited = new HashSet<>();
Deque<String> queue = new ArrayDeque<>();
visited.add(beginWord);
queue.offer(beginWord);
int ans = 1;
while (!queue.isEmpty()) {
int size = queue.size();
++ans;
for (int i = 0; i < size; ++i) {
String start = queue.poll();
for (String s : wordList) {
if (visited.contains(s)) continue; // 已经访问过,跳过
if (!canConvert(start, s)) continue; // 不能转换,跳过
if (s.equals(endWord)) return ans;
visited.add(s);
queue.offer(s);
}
}
}
return 0;
}

private boolean canConvert(String start, String end) {
int cnt = 0;
for (int i = 0; i < start.length(); ++i) {
if (start.charAt(i) != end.charAt(i)) ++cnt;
if (cnt > 1) return false;
}
return true;
}
}

方法二:BFS(优化visited)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
if (!wordList.contains(endWord)) return 0;
boolean[] visited = new boolean[wordList.size()];
int index = wordList.indexOf(beginWord);
if (index != -1) visited[index] = true;
Deque<String> queue = new ArrayDeque<>();
queue.offer(beginWord);
int ans = 1;
while (!queue.isEmpty()) {
int size = queue.size();
++ans;
for (int i = 0; i < size; ++i) {
String start = queue.poll();
for (int j = 0; j < wordList.size(); ++j) {
if (visited[j]) continue; // 已经访问过,跳过
String s = wordList.get(j);
if (!canConvert(start, s)) continue; // 不能转换,跳过
if (s.equals(endWord)) return ans;
visited[j] = true;
queue.offer(s);
}
}
}
return 0;
}

private boolean canConvert(String start, String end) {
int cnt = 0;
for (int i = 0; i < start.length(); ++i) {
if (start.charAt(i) != end.charAt(i)) ++cnt;
if (cnt > 1) return false;
}
return true;
}
}

方法三:双向BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
int index = wordList.indexOf(endWord);
if (index == -1) return 0;

wordList.add(beginWord);
Deque<String> queue1 = new ArrayDeque<>();
Deque<String> queue2 = new ArrayDeque<>();
Set<String> visited1 = new HashSet<>();
Set<String> visited2 = new HashSet<>();
queue1.offer(beginWord);
queue2.offer(endWord);
visited1.add(beginWord);
visited2.add(endWord);

int ans = 1;
Set<String> wordSet = new HashSet<>(wordList);

while (!queue1.isEmpty() && !queue2.isEmpty()) {
++ans;
// 从节点更少的一端开始遍历
if (queue1.size() > queue2.size()) {
Deque<String> tmp = queue1;
queue1 = queue2;
queue2 = tmp;
Set<String> t = visited1;
visited1 = visited2;
visited2 = t;
}
int size1 = queue1.size();
while (size1-- > 0) {
String s = queue1.poll();
char[] chars = s.toCharArray();
for (int i = 0; i < s.length(); ++i) {
// 保存第i位的原始字符
char c0 = chars[i];
for (char c = 'a'; c <= 'z'; ++c) {
chars[i] = c;
String newString = new String(chars);
if (visited1.contains(newString)) continue; // 已经访问过了,跳过
if (visited2.contains(newString)) return ans; // 两端遍历相遇,结束遍历,返回 count
// 如果单词在列表中存在,将其添加到队列,并标记为已访问
if (wordSet.contains(newString)) {
queue1.offer(newString);
visited1.add(newString);
}
}
// 恢复第i位的原始字符
chars[i] = c0;
}
}
}
return 0;
}
}