考虑使用位运算压缩的做法。
Java 代码:
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
public class Solution {
// 推荐的,固定模式的写法
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
// wordList 中如果有 beginWord 应该删除,用哈希表便于查找和修改
Set<String> hashSet = new HashSet<>(wordList);
hashSet.remove(beginWord);
// BFS 必须使用队列
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
int step = 1;
while (!queue.isEmpty()) {
int currentSize = queue.size();
for (int i = 0; i < currentSize; i++) {
// 依次遍历当前队列中的单词
String word = queue.poll();
int len = word.length();
char[] charArray = word.toCharArray();
// 修改每一个字符
for (int j = 0; j < len; j++) {
// 一轮以后应该重置,否则结果不正确
char currentChar = charArray[j];
for (char k = 'a'; k <= 'z'; k++) {
charArray[j] = k;
String temp = String.valueOf(charArray);
if (hashSet.contains(temp)) {
if (temp.equals(endWord)) {
return step + 1;
}
queue.add(temp);
// 找到了以后,下一次就不是目标了,所以要删除
hashSet.remove(temp);
}
}
// 恢复,下次再用
charArray[j] = currentChar;
}
}
step++;
}
return 0;
}
}
下面这两种写法都是把层数封装在一起写的,非标准写法。
Java 代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
public class Solution {
// 非标准 BFS 的写法
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<Pair> queue = new LinkedList<>();
queue.offer(new Pair(beginWord, 1));
Set<String> visited = new HashSet<>();
visited.add(beginWord);
while (!queue.isEmpty()) {
Pair curPair = queue.poll();
String curWord = curPair.word;
Integer step = curPair.step;
step++;
List<String> nextWords = onlyChangeOne(curWord, wordList, visited);
for (String nextWord : nextWords) {
if (nextWord.equals(endWord)) {
return step;
}
queue.offer(new Pair(nextWord, step));
visited.add(nextWord);
}
}
return 0;
}
private List<String> onlyChangeOne(String word, List<String> wordList, Set<String> visited) {
// 与 word 相差一个字母的 wordList 的元素有哪些,并且要保证没有使用过
List<String> res = new ArrayList<>();
int len = word.length();
for (String match : wordList) {
int count = 0;
for (int i = 0; i < len; i++) {
if (word.charAt(i) != match.charAt(i)) {
count++;
// 如果不同的字母的数量已经大于 1 个,那么它就肯定不是我们要找的单词
if (count >= 2) {
break;
}
}
}
// 恰好相差一个字符,且还未被访问过,才是邻居
if (count == 1 && !visited.contains(match)) {
res.add(match);
}
}
return res;
}
private class Pair {
private String word;
private Integer step;
public Pair(String word, Integer step) {
this.word = word;
this.step = step;
}
}
public static void main(String[] args) {
List<String> wordList = new ArrayList<>();
String[] words = {
"hot", "dot", "dog", "lot", "log", "cog"};
Collections.addAll(wordList, words);
Solution solution = new Solution();
String beginWord = "hit";
String endWord = "cog";
int ladderLength = solution.ladderLength(beginWord, endWord, wordList);
System.out.println(String.format("从 %s 到 %s 的最短转换序列的长度:%d。", beginWord, endWord, ladderLength));
}
}
Java 代码:
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
public class Solution {
// 这种写法 map 很累赘,不推荐
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
// wordList 中如果有 beginWord 应该删除
Set<String> set = new HashSet<>(wordList);
set.remove(beginWord);
// BFS 必须使用队列
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
Map<String, Integer> map = new HashMap<>();
map.put(beginWord, 1);
while (!queue.isEmpty()) {
// 从队列首出队
String word = queue.poll();
int curStep = map.get(word);
for (int i = 0; i < word.length(); i++) {
char[] charArray = word.toCharArray();
for (char j = 'a'; j <= 'z'; j++) {
charArray[i] = j;
String temp = new String(charArray);
if (set.contains(temp)) {
if (temp.equals(endWord)) {
return curStep + 1;
}
map.put(temp, curStep + 1);
queue.offer(temp);
set.remove(temp);
}
}
}
}
return 0;
}
}
没看懂的做法:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
public class Solution {
// 编码太复杂,不推荐
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
int len = beginWord.length();
Map<String, ArrayList<String>> allComboDict = new HashMap<>();
for (String s : wordList) {
for (int i = 0; i < len; i++) {
// 得到这个单词所有的模式
String newWord = s.substring(0, i) + '*' + s.substring(i + 1, len);
ArrayList<String> transformations = allComboDict.getOrDefault(newWord, new ArrayList<>());
transformations.add(s);
allComboDict.put(newWord, transformations);
}
}
// 预处理
Set<Map.Entry<String, ArrayList<String>>> entries = allComboDict.entrySet();
for (Map.Entry<String, ArrayList<String>> map : entries) {
System.out.println(map.getKey() + " " + map.getValue());
}
Queue<Pair<String, Integer>> queue = new LinkedList<>();
queue.add(new Pair<>(beginWord, 1));
Map<String, Boolean> visited = new HashMap<>();
visited.put(beginWord, true);
while (!queue.isEmpty()) {
Pair<String, Integer> node = queue.poll();
String word = node.getKey();
int level = node.getValue();
for (int i = 0; i < len; i++) {
// 拿出这个单词所有的模式
String newWord = word.substring(0, i) + '*' + word.substring(i + 1, len);
for (String adjacentWord : allComboDict.getOrDefault(newWord, new ArrayList<String>())) {
if (adjacentWord.equals(endWord)) {
return level + 1;
}
if (!visited.containsKey(adjacentWord)) {
visited.put(adjacentWord, true);
queue.add(new Pair<>(adjacentWord, level + 1));
}
}
}
}
return 0;
}
private class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
}