Leetcode 127.单词接龙

单词接龙

给定两个单词(beginWord endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWordendWord 是非空的,且二者不相同。

示例 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 }

猜你喜欢

转载自www.cnblogs.com/kexinxin/p/10187802.html