介绍
标签:广度搜索
建议使用双向广度搜索并优化图遍历
leetcode57 - 插入区间
难度 中等
单词接龙
https://leetcode-cn.com/problems/word-ladder/
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
- 每次转换只能改变一个字母。
- 转换过程中的中间单词必须是字典中的单词。
说明:
- 如果不存在这样的转换序列,返回 0。
- 所有单词具有相同的长度。
- 所有单词只由小写字母组成。
- 字典中不存在重复的单词。
- 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 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” 不在字典中,所以无法进行转换。
解题思路
朴素主义写法:
在这种情况下去寻找只改变一个字母的下一个单词,与其去遍历数组,还不如将每一位替换来得快,尤其是在传入大量数据的时候
- 建立队列,用于后面的广度搜索,并将初始元素入队。
- 建立哈希映射,用于记录那个单词是否被访问过,同时保存对应的路径长
- 开始广度搜索,遍历每个单词
- 在当前单词遍历每一位的字母,同时在将其替换为a-z的每一个字母进行尝试
- 当发现能匹配目标单词的时候直接输出当前保存的路径+1
- 当发现能匹配数组中的单词时,入队,并将当前路径+1存入哈希映射
- 其他情况不管,继续遍历
- 当全部遍历了一遍时,直接return 0,查找失败
代码
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//首先将数组转换为哈希表提高效率
HashSet<String> wordSet = new HashSet<>(wordList);
//判断出特殊情况
if (wordSet.size() == 0 || !wordSet.contains(endWord))
return 0;
//广度搜索使用的队列
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);//将第一个单词入队
//记录每个单词对应路径长度
Map<String, Integer> map = new HashMap<>();
map.put(beginWord, 1);
//用while进行广度搜索
while (!queue.isEmpty()) {
//取出对首元素,开始判断
String word = queue.poll();
int path = map.get(word); //获取到该单词的路径长度
//遍历每个字符尝试替换
for (int i = 0; i < word.length(); i++) {
// //将单词从String转换为char array,用于替换
char[] chars = word.toCharArray();
//将当前为字符替换为a-k,全部试一次
for (char k = 'a'; k <= 'z'; k++) {
chars[i] = k;
String newWord = String.valueOf(chars);
//当遍历到结尾的时候,直接返回当前长度+1
if (newWord.equals(endWord)) {
return path + 1;
}
//发现改变之后的单词在传入的单词列表中,并且没有访问过时
if (wordSet.contains(newWord) && !map.containsKey(newWord)) {
//记录长度
map.put(newWord, path + 1);
//加入队尾,准备下一轮的遍历
queue.offer(newWord);
}
}
}
}
return 0;
}
}