Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
Solution:
Breadth First Search.
起个好的变量名多么的重要啊。我看到网上写的好多代码,那变量名起的太有混淆的反作用了。
- 和当前单词相邻的单词是:对当前单词改变一个字母且在字典中存在的单词
- 找到一个单词的相邻单词,加入bfs队列后,要从字典中删除,因为不删除的话会造成类似于hog->hot->hog的死循环。而删除对求最短路径没有影响,因为我们第一次找到该单词肯定是最短路径,即使后面其他单词也可能转化得到它,路径肯定不会比当前的路径短(如果要输出所有最短路径,则不能立即从字典中删除)
- bfs队列中用width==0来标识层与层的间隔,每次碰到width==0,遍历深度+1
这个算法中最坏情况是把所有长度为L的字符串都看一下,或者把字典中的字符串都看一下,而长度为L的字符串总共有26^L,所以时间复杂度是O(min(26^L, size(dict)),空间上需要存储访问情况,也是O(min(26^L, size(dict))。
public int ladderLength(String start, String end, HashSet<String> dict) { if (dict == null || dict.size() == 0) return 0; Queue<String> queue = new LinkedList<String>(); queue.offer(start); dict.remove(start); int depth = 1; // ladder的深度 int width = 1; // 层的宽度,即每一层变换的单词的总数量 while(!queue.isEmpty()) { char[] str = queue.poll().toCharArray(); for (int i=0; i < str.length; i++) { for (char c = 'a'; c <= 'z'; c++) { if(str[i] == c) continue; char tmp = str[i]; str[i] = c; String word = new String(str); if (word.equals(end)) return depth + 1; if (dict.remove(word)){ //当该单词在词典中,删除并返回true;若不存在该单词则返回false queue.offer(word); } str[i] = tmp; } } if(--width == 0) { width = queue.size(); //更新为下一层变换的单词的数量 depth++; } } return 0; }