本文主要是介绍LeetCode题练习与总结:单词接龙--127,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、题目描述
字典 wordList
中从单词 beginWord
和 endWord
的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk
:
- 每一对相邻的单词只差一个字母。
- 对于
1 <= i <= k
时,每个si
都在wordList
中。注意,beginWord
不需要在wordList
中。 sk == endWord
给你两个单词 beginWord
和 endWord
和一个字典 wordList
,返回 从 beginWord
到 endWord
的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 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
beginWord
、endWord
和wordList[i]
由小写英文字母组成beginWord != endWord
wordList
中的所有字符串 互不相同
二、解题思路
-
将单词列表转换为图:首先,我们需要构建一个图,其中包含
wordList
中的所有单词。这可以通过比较每对单词并检查它们是否只有一个字符不同来实现。 -
广度优先搜索:从
beginWord
开始,进行广度优先搜索,寻找endWord
。在搜索过程中,我们记录从beginWord
到当前单词的路径长度。 -
终止条件:一旦我们找到了
endWord
,我们就知道我们已经找到了最短的转换序列,并且可以返回当前的路径长度。 -
优化:为了提高搜索效率,我们可以在开始 BFS 之前预处理
wordList
,创建一个通用状态映射,这样我们可以快速找到所有与给定单词只有一个字符差异的单词。
三、具体代码
import java.util.*;public class Solution {public int ladderLength(String beginWord, String endWord, List<String> wordList) {// 将单词列表转换为集合,便于快速查找Set<String> wordSet = new HashSet<>(wordList);if (!wordSet.contains(endWord)) return 0;// BFS 队列Queue<String> queue = new LinkedList<>();queue.offer(beginWord);// 记录已访问的单词Set<String> visited = new HashSet<>();visited.add(beginWord);// 记录转换序列的长度int level = 1;while (!queue.isEmpty()) {int size = queue.size();for (int i = 0; i < size; i++) {String currentWord = queue.poll();// 如果找到了结束单词if (currentWord.equals(endWord)) {return level;}// 遍历当前单词的所有可能转换for (String nextWord : getNextWords(currentWord, wordSet)) {if (!visited.contains(nextWord)) {queue.offer(nextWord);visited.add(nextWord);}}}level++;}return 0;}// 获取当前单词的所有可能转换private List<String> getNextWords(String word, Set<String> wordSet) {List<String> nextWords = new ArrayList<>();for (char ch = 'a'; ch <= 'z'; ch++) {for (int i = 0; i < word.length(); i++) {// 生成下一个可能的单词String nextWord = replace(word, i, ch);if (wordSet.contains(nextWord)) {nextWords.add(nextWord);}}}return nextWords;}// 替换单词中的某个字符private String replace(String word, int index, char ch) {char[] chars = word.toCharArray();chars[index] = ch;return new String(chars);}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
-
构建
wordSet
:将wordList
转换为HashSet
的时间复杂度是 O(N),其中 N 是wordList
的长度。 -
BFS 遍历:在 BFS 过程中,每个单词都可能生成 26 * L 个新单词,其中 L 是单词的长度。在最坏的情况下,所有单词都可能被访问一次。因此,时间复杂度是 O(N * 26 * L)。
-
getNextWords
函数:对于每个单词,我们检查 26 * L 个可能的转换。这个操作的时间复杂度是 O(26 * L)。 -
replace
函数:这个函数的时间复杂度是 O(L),因为我们只是替换了一个字符并生成了一个新的字符串。 -
综上所述,总的时间复杂度是 O(N * 26 * L)。
2. 空间复杂度
-
wordSet
和visited
:这两个HashSet
最多存储 N 个单词,因此它们的空间复杂度是 O(N)。 -
队列
queue
:在 BFS 过程中,队列中最多可能存储 N 个单词,因此空间复杂度是 O(N)。 -
nextWords
列表:在getNextWords
函数中,这个列表最多可能存储 26 * L 个单词,因此空间复杂度是 O(26 * L)。 -
其他变量:如
level
和循环中的临时变量等,它们的空间复杂度是 O(1)。 -
综上所述,总的空间复杂度是 O(N + 26 * L)。
综合来看,这个算法的时间复杂度是 O(N * 26 * L),空间复杂度是 O(N + 26 * L)。
五、总结知识点
-
集合的使用:
HashSet
用于存储不重复的元素,并提供了快速的查找、添加和删除操作。代码中使用了HashSet
来存储wordList
和已访问的单词。 -
队列的使用:
LinkedList
作为队列使用,实现了先进先出的数据结构。在 BFS 过程中,队列用于存储待访问的单词。 -
广度优先搜索(BFS):这是一种图遍历算法,用于在图中找到最短路径。代码中使用了 BFS 来找到从
beginWord
到endWord
的最短转换序列。 -
字符串操作:
replace
函数展示了如何通过索引替换字符串中的字符。这涉及到字符串转字符数组,然后修改数组中的元素,最后将数组转回字符串。 -
循环和条件语句:代码中使用了
for
循环来遍历单词的每个字符和字母表中的每个字符,以及if
语句来检查条件。 -
函数定义和调用:代码中定义了
ladderLength
、getNextWords
和replace
三个函数,分别用于解决不同的问题。函数的定义和调用展示了模块化编程的思想。 -
字符和字符数组:代码中使用了字符变量
ch
来遍历字母表,并使用了字符数组chars
来表示和操作字符串。 -
数据结构的选择:代码中选择合适的数据结构(如
HashSet
和Queue
)来优化算法的性能,特别是在单词查找和图遍历方面。 -
算法设计:代码实现了基于 BFS 的图遍历算法,这是一种常见的算法设计技巧,用于解决最短路径问题。
-
递归和迭代:虽然代码中没有直接使用递归,但 BFS 本身是一种递归思想的迭代实现,每次迭代都相当于展开递归的一层。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。
这篇关于LeetCode题练习与总结:单词接龙--127的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!