自己做
解:递归选取(超时)
java
复制代码
class Solution {
private int min_len = Integer.MAX_VALUE;
private List<Boolean> choice; //标记是否选取
private List<List<String>> res; //存在结果
public void searchWord(String endWord, List<String> wordList, List<Boolean> option, List<String> combine){
if(combine.size() > min_len) //比最短组合长也没必要继续往下延伸了
return;
List<String> combination = new ArrayList(combine);
List<Boolean> choice = new ArrayList(option);
if(combination.get(combination.size() - 1).equals(endWord)){ //组合中最后一个元素和endWord相同即找到了对应组合
if(res.size() == 0){ //第一个组合,直接加入
res.add(combination);
min_len = combination.size();
}
else{ //不是第一个组合,综合考虑
if(combination.size() < min_len){ //找到了更短的序列,更新res
min_len = combination.size();
//清空以前的结果,以目前最短的为准
res = new ArrayList();
res.add(combination);
}
else if(combination.size() == min_len) //找到了同样短的序列,加入res
res.add(combination);
//比最短组合长的组合就不考虑了
}
return;
}
//选取这一层的元素
for(int i = 0; i < wordList.size(); i++){
if(!choice.get(i)){ //没有被选取过的元素
//检查上个单词和当前单词不一样的字母数
int num = 0;
for(int j = 0; j < combination.get(combination.size() - 1).length(); j++)
if(wordList.get(i).charAt(j) != combination.get(combination.size() - 1).charAt(j))
num++;
if(num == 1){ //相差一个字母,尝试选取
combination.add(wordList.get(i));
choice.set(i, true);
searchWord(endWord, wordList, choice, combination); //放入组合
choice.set(i, false);
combination.remove(combination.size() - 1);
}
//除此之外都不选取
}
}
}
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
//检查endWord是否在wordList中
boolean is_exist = false;
choice = new ArrayList();
for(int i = 0; i < wordList.size(); i++){ //检查的同时顺便初始化choice
if(endWord.equals(wordList.get(i))) //存在
is_exist = true;
choice.add(false);
}
if(!is_exist) //不存在就直接返回
return new ArrayList();
res = new ArrayList();
List<String> combination = new ArrayList<String>();
combination.add(beginWord);
searchWord(endWord, wordList, choice, combination);
return res;
}
}
看题解
java
复制代码
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> res = new ArrayList<>();
// 因为需要快速判断扩展出的单词是否在 wordList 里,因此需要将 wordList 存入哈希表,这里命名为「字典」
Set<String> dict = new HashSet<>(wordList);
// 特殊用例判断
if (!dict.contains(endWord)) {
return res;
}
dict.remove(beginWord);
// 第 1 步:广度优先搜索建图
// 记录扩展出的单词是在第几次扩展的时候得到的,key:单词,value:在广度优先搜索的第几层
Map<String, Integer> steps = new HashMap<String, Integer>();
steps.put(beginWord, 0);
// 记录了单词是从哪些单词扩展而来,key:单词,value:单词列表,这些单词可以变换到 key ,它们是一对多关系
Map<String, List<String>> from = new HashMap<String, List<String>>();
int step = 1;
boolean found = false;
int wordLen = beginWord.length();
Queue<String> queue = new ArrayDeque<String>();
queue.offer(beginWord);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
String currWord = queue.poll();
char[] charArray = currWord.toCharArray();
// 将每一位替换成 26 个小写英文字母
for (int j = 0; j < wordLen; j++) {
char origin = charArray[j];
for (char c = 'a'; c <= 'z'; c++) {
charArray[j] = c;
String nextWord = String.valueOf(charArray);
if (steps.containsKey(nextWord) && step == steps.get(nextWord)) {
from.get(nextWord).add(currWord);
}
if (!dict.contains(nextWord)) {
continue;
}
// 如果从一个单词扩展出来的单词以前遍历过,距离一定更远,为了避免搜索到已经遍历到,且距离更远的单词,需要将它从 dict 中删除
dict.remove(nextWord);
// 这一层扩展出的单词进入队列
queue.offer(nextWord);
// 记录 nextWord 从 currWord 而来
from.putIfAbsent(nextWord, new ArrayList<>());
from.get(nextWord).add(currWord);
// 记录 nextWord 的 step
steps.put(nextWord, step);
if (nextWord.equals(endWord)) {
found = true;
}
}
charArray[j] = origin;
}
}
step++;
if (found) {
break;
}
}
// 第 2 步:回溯找到所有解,从 endWord 恢复到 beginWord ,所以每次尝试操作 path 列表的头部
if (found) {
Deque<String> path = new ArrayDeque<>();
path.add(endWord);
backtrack(from, path, beginWord, endWord, res);
}
return res;
}
public void backtrack(Map<String, List<String>> from, Deque<String> path, String beginWord, String cur, List<List<String>> res) {
if (cur.equals(beginWord)) {
res.add(new ArrayList<>(path));
return;
}
for (String precursor : from.get(cur)) {
path.addFirst(precursor);
backtrack(from, path, beginWord, precursor, res);
path.removeFirst();
}
}
}、