单词接龙
给定两个单词(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" 不在字典中,所以无法进行转换。
这是很典型的单源头广度优先搜索最短路径的问题,只要想到这里,结合图的知识就很好做了。怎么构建图呢?首先图的顶点显而易见,就是每一个单词。那么顶点之间的边呢?就是如果顶点的单词互相只差一个字母,顶点间就会形成边。用第一个例子绘制的图如下:
那么根据广度优先搜索的步骤,构建一个队列,之后先把源顶点加入队列,以队列是否为空作为条件开始循环:如果队列不为空,逐个取出队列中的顶点,并把它们标记为"已访问"。对于每个取出的顶点,依次把它未访问的顶点加入队列,直到找到目标顶点或者所有顶点都访问完毕。因为此题只是求最短路径的长度,而不是路径上都有哪些顶点,所以只需要存储每访问一个顶点时该顶点处在路径的位置即可。这里我用了HashMap<String, Integer>。如果是需要存储最短路径本身,那么需要建立数据结构依次存储每个顶点的前驱,并在最后追溯前驱获得路径上的所有顶点。
这里我用一个HashSet替换掉题目中存储单词的List数据结构,只是为了搜索的时候能够快一点。至于如何获取某个节点的邻接节点,即和它只差一个字母的单词,这里用了最暴力的办法,就是把顶点单词的每一位换成其他的25个字母,看看它在不在题目提供的字典里。详细的标注都已经标注在代码中,见下。
1 class Solution{ 2 public int ladderLength(String beginWord,String endWord,List<String> wordList){ 3 HashSet<String> wordSet=new HashSet<>(wordList);//替换题目中List结构,加速查找 4 if(!wordSet.contains(endWord)) return 0; 5 HashMap<String,Integer> map=new HashMap<>();//用来存储已访问的节点,并存储其在路径上的位置,相当于BFS算法中的isVisted功能 6 Queue<String> q=new LinkedList<>();//构建队列,实现广度优先遍历。 7 q.add(beginWord);//加入源顶点 8 map.put(beginWord,1);//添加原顶点为“已访问”,并记录它在路径的位置 9 while(!q.isEmpty()){ 10 String word=q.poll();//记录正在处理的顶点 11 int level=map.get(word);//记录现在路径的长度 12 for(int i=0;i<word.length();i++){ 13 char[] wordLetter=word.toCharArray(); 14 for(char j='a';j<='z';j++){ 15 if(wordLetter[i]==j) continue; 16 wordLetter[i]=j;//对于每一位字母,分别替换成另外25个字母 17 String check=new String(wordLetter); 18 if(check.equals(endWord)) return map.get(word)+1;//如果已经抵达目标节点,返回当前路径长度+1 19 if(wordSet.contains(check)&&!map.containsKey(check)){//如果字典中存在邻接节点,且这个邻接节点还未被访问 20 map.put(check,level+1);//标记这个邻接节点为已访问,记录其在路径上的位置 21 q.add(check);//加入队列,以供广度搜索 22 } 23 } 24 } 25 } 26 return 0; 27 } 28 }