解题思路:
1 这道题要找一个最短路径,可以联想到图的相关算法(虽然我当时没想到…),那么是不是应该使用最短路径的相关算法呢。其实不用…因为这个图里每条边的长度都是1,用一个广度优先算法就搞定了。
2 规模的问题,如果你遍历List里的每个单词的话,你会发现一直超时,因为有的List的规模给到了上千,每次查找图中的相邻节点都会是一个O(n)。解决办法是对规模很大的List,给每个当前操作单词建立一个“可相邻集”,即把每个字母都替换成其他25个字母,这样的话,两种策略可以保证较好的时间复杂度。
代码:
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
//有效性检查
if (!wordList.contains(endWord))
return 0;
Set<String> wordSet = new HashSet(wordList);
//用于图遍历的队列
Queue<String> wordsInQ = new LinkedList<>();
//用于记录路径长度的Map
Map<String, Integer> pathLength = new HashMap<>();
//对不同规模的wordList 采取不同策略
boolean isLarge = wordList.size()>75?true:false;
//将开始的单词入队 设置路径长度为1 设置为已访问
wordsInQ.add(beginWord);
pathLength.put(beginWord, 1);
while (!wordsInQ.isEmpty()){
//最前面的单词出队 并获取当前长度
String nowWord = wordsInQ.poll();
int nowLength = pathLength.get(nowWord);
if (!isLarge){
for (String word : wordSet){
if (canLad(nowWord, word)){
//到终点了 返回长度+1
if (word.equals(endWord))
return pathLength.get(nowWord) + 1;
//word未被访问
if (!pathLength.containsKey(word)){
pathLength.put(word, nowLength + 1);
wordsInQ.add(word);
}
}
}
}else {
//对当前单词的每个字母进行替换
for (int i = 0;i < nowWord.length();i++){
char[] nowWordArray = nowWord.toCharArray();
//替换成其他25个字母
for (char j = 'a';j <= 'z';j++){
if (nowWordArray[i] == j) continue;
nowWordArray[i] = j;
//
String word = new String(nowWordArray);
// System.out.println(word);
//到终点了 返回长度+1
if (word.equals(endWord))
return pathLength.get(nowWord) + 1;
//word在List里且未被访问
if (wordSet.contains(word) && !pathLength.containsKey(word)){
pathLength.put(word, nowLength + 1);
wordsInQ.add(word);
}
}
}
}
}
return 0;
}
private boolean canLad(String nowWord, String nextWord){
int length = nowWord.length();
int times = 0;
for (int i = 0;i < length;i++){
if (nowWord.charAt(i) != nextWord.charAt(i)){
times++;
}
}
return times == 1;
}
}