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
Notice
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
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.
思路
找最短路径,可以将已知的word看成一个graph,找这个graph的最短路径。但问题是这个graph并未告知,需要自己找。
关键点有3:
- 如何找当前word的邻居:26个字母依次替换
由于题目说2个相关单词只能是差别一个字母,那么我们可以遍历当前单词的每一个字母,将该字母逐一替换成a – z,然后看这替换过的26个单词是否在已知的dict中,如果是,则这些单词就是当前单词的邻居。- 单独写一个函数来返回当前word的neighbors:List
- 把这些neighbor单词加到queue中,作为当前层来判断,该层中是否有target。
- 单独写一个函数来返回当前word的neighbors:List
- 如何标记已经遍历过的单词: hashset去重
比如我们已经找到hit的邻居是hot,当我们在找hot的邻居的时候,因为hit已经被遍历过了,就不能再遍历了,不能被返回为neighbors。- 可以用set来标记已经找到过的单词。 认为,加入queue的,就是已经找到过的了。
- 在找neighbors的时候,判断当前词是否在set中已经存在,如果存在,则跳过它。
- 不要忘记求shortest path其实是求一共多少层,需要加一层 loop循环 queue.size()
public class Solution {
/**
* @param start, a string
* @param end, a string
* @param dict, a set of string
* @return an integer
*/
public int ladderLength(String start, String end, Set dict) {
if (dict == null) {
return 0;
}
if (start.equals(end)) {
return 1;
}
// 需要把已知的start和end都加入到dict中,这样才能在后续的找当前单词的邻居时,找到end。
dict.add(end);
Queue queue = new LinkedList();
Set set = new HashSet();
queue.add(start);
set.add(start);
List neighbors = new ArrayList();
int size = 0;
int len = 1;
while (!queue.isEmpty()) {
size = queue.size();
len++;
for (int i = 0; i < size; i++) {
String curStr = queue.poll();
neighbors = this.getNeighbors(curStr, dict, set);
for (String neighbor : neighbors) {
if (neighbor.equals(end)) {
return len;
}
queue.add(neighbor);
set.add(neighbor);
}
}
}
return -1;
}
private List getNeighbors(String curStr, Set dict, Set set) {
List neighbors = new ArrayList();
for (int i = 0; i < curStr.length(); i++) {
for (char c = 'a'; c <= 'z'; c++) {
//是它自己就跳过,因为不是他自己的变形
if (curStr.charAt(i) == c) {
continue;
}
//单词逐个字母替换, temp必须是每次重新从curStr中获取,否则会被上一次结果污染
char[] temp = curStr.toCharArray();
temp[i] = c;
String curStrTemp = String.valueOf(temp);
if (dict.contains(curStrTemp) && set.contains(curStrTemp) != true) {
neighbors.add(curStrTemp);
}
}
}
return neighbors;
}
}