剑指 Offer II 108. 单词演变
在字典(单词列表) wordList
中,从单词 beginWord
和 endWord
的 转换序列 是一个按下述规格形成的序列:
beginWord
。endWord
。wordList
中的单词。给定两个长度相同但内容不同的单词 beginWord
和 endWord
和一个字典 wordList
,找到从 beginWord
到 endWord
的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。
示例 1:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出:5 解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
示例 2:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"] 输出:0 解释:endWord "cog" 不在字典中,所以无法进行转换。
提示:
1 <= beginWord.length <= 10
endWord.length == beginWord.length
1 <= wordList.length <= 5000
wordList[i].length == beginWord.length
beginWord
、endWord
和 wordList[i]
由小写英文字母组成beginWord != endWord
wordList
中的所有字符串 互不相同
注意:本题与主站 127 题相同: https://leetcode.cn/problems/word-ladder/
原站题解
golang 解法, 执行用时: 32 ms, 内存消耗: 8.6 MB, 提交时间: 2023-04-22 12:25:55
func ladderLength(beginWord string, endWord string, wordList []string) int { wordId := map[string]int{} graph := [][]int{} addWord := func(word string) int { id, has := wordId[word] if !has { id = len(wordId) wordId[word] = id graph = append(graph, []int{}) } return id } addEdge := func(word string) int { id1 := addWord(word) s := []byte(word) for i, b := range s { s[i] = '*' id2 := addWord(string(s)) graph[id1] = append(graph[id1], id2) graph[id2] = append(graph[id2], id1) s[i] = b } return id1 } for _, word := range wordList { addEdge(word) } beginId := addEdge(beginWord) endId, has := wordId[endWord] if !has { return 0 } const inf int = math.MaxInt64 distBegin := make([]int, len(wordId)) for i := range distBegin { distBegin[i] = inf } distBegin[beginId] = 0 queueBegin := []int{beginId} distEnd := make([]int, len(wordId)) for i := range distEnd { distEnd[i] = inf } distEnd[endId] = 0 queueEnd := []int{endId} for len(queueBegin) > 0 && len(queueEnd) > 0 { q := queueBegin queueBegin = nil for _, v := range q { if distEnd[v] < inf { return (distBegin[v]+distEnd[v])/2 + 1 } for _, w := range graph[v] { if distBegin[w] == inf { distBegin[w] = distBegin[v] + 1 queueBegin = append(queueBegin, w) } } } q = queueEnd queueEnd = nil for _, v := range q { if distBegin[v] < inf { return (distBegin[v]+distEnd[v])/2 + 1 } for _, w := range graph[v] { if distEnd[w] == inf { distEnd[w] = distEnd[v] + 1 queueEnd = append(queueEnd, w) } } } } return 0 }
python3 解法, 执行用时: 108 ms, 内存消耗: 20.6 MB, 提交时间: 2023-04-22 12:25:39
class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: def addWord(word: str): if word not in wordId: nonlocal nodeNum wordId[word] = nodeNum nodeNum += 1 def addEdge(word: str): addWord(word) id1 = wordId[word] chars = list(word) for i in range(len(chars)): tmp = chars[i] chars[i] = "*" newWord = "".join(chars) addWord(newWord) id2 = wordId[newWord] edge[id1].append(id2) edge[id2].append(id1) chars[i] = tmp wordId = dict() edge = collections.defaultdict(list) nodeNum = 0 for word in wordList: addEdge(word) addEdge(beginWord) if endWord not in wordId: return 0 disBegin = [float("inf")] * nodeNum beginId = wordId[beginWord] disBegin[beginId] = 0 queBegin = collections.deque([beginId]) disEnd = [float("inf")] * nodeNum endId = wordId[endWord] disEnd[endId] = 0 queEnd = collections.deque([endId]) while queBegin or queEnd: queBeginSize = len(queBegin) for _ in range(queBeginSize): nodeBegin = queBegin.popleft() if disEnd[nodeBegin] != float("inf"): return (disBegin[nodeBegin] + disEnd[nodeBegin]) // 2 + 1 for it in edge[nodeBegin]: if disBegin[it] == float("inf"): disBegin[it] = disBegin[nodeBegin] + 1 queBegin.append(it) queEndSize = len(queEnd) for _ in range(queEndSize): nodeEnd = queEnd.popleft() if disBegin[nodeEnd] != float("inf"): return (disBegin[nodeEnd] + disEnd[nodeEnd]) // 2 + 1 for it in edge[nodeEnd]: if disEnd[it] == float("inf"): disEnd[it] = disEnd[nodeEnd] + 1 queEnd.append(it) return 0
java 解法, 执行用时: 23 ms, 内存消耗: 49.4 MB, 提交时间: 2023-04-22 12:25:28
// 双向广度优先搜索 class Solution { Map<String, Integer> wordId = new HashMap<String, Integer>(); List<List<Integer>> edge = new ArrayList<List<Integer>>(); int nodeNum = 0; public int ladderLength(String beginWord, String endWord, List<String> wordList) { for (String word : wordList) { addEdge(word); } addEdge(beginWord); if (!wordId.containsKey(endWord)) { return 0; } int[] disBegin = new int[nodeNum]; Arrays.fill(disBegin, Integer.MAX_VALUE); int beginId = wordId.get(beginWord); disBegin[beginId] = 0; Queue<Integer> queBegin = new LinkedList<Integer>(); queBegin.offer(beginId); int[] disEnd = new int[nodeNum]; Arrays.fill(disEnd, Integer.MAX_VALUE); int endId = wordId.get(endWord); disEnd[endId] = 0; Queue<Integer> queEnd = new LinkedList<Integer>(); queEnd.offer(endId); while (!queBegin.isEmpty() && !queEnd.isEmpty()) { int queBeginSize = queBegin.size(); for (int i = 0; i < queBeginSize; ++i) { int nodeBegin = queBegin.poll(); if (disEnd[nodeBegin] != Integer.MAX_VALUE) { return (disBegin[nodeBegin] + disEnd[nodeBegin]) / 2 + 1; } for (int it : edge.get(nodeBegin)) { if (disBegin[it] == Integer.MAX_VALUE) { disBegin[it] = disBegin[nodeBegin] + 1; queBegin.offer(it); } } } int queEndSize = queEnd.size(); for (int i = 0; i < queEndSize; ++i) { int nodeEnd = queEnd.poll(); if (disBegin[nodeEnd] != Integer.MAX_VALUE) { return (disBegin[nodeEnd] + disEnd[nodeEnd]) / 2 + 1; } for (int it : edge.get(nodeEnd)) { if (disEnd[it] == Integer.MAX_VALUE) { disEnd[it] = disEnd[nodeEnd] + 1; queEnd.offer(it); } } } } return 0; } public void addEdge(String word) { addWord(word); int id1 = wordId.get(word); char[] array = word.toCharArray(); int length = array.length; for (int i = 0; i < length; ++i) { char tmp = array[i]; array[i] = '*'; String newWord = new String(array); addWord(newWord); int id2 = wordId.get(newWord); edge.get(id1).add(id2); edge.get(id2).add(id1); array[i] = tmp; } } public void addWord(String word) { if (!wordId.containsKey(word)) { wordId.put(word, nodeNum++); edge.add(new ArrayList<Integer>()); } } }
java 解法, 执行用时: 25 ms, 内存消耗: 49.3 MB, 提交时间: 2023-04-22 12:24:57
class Solution { Map<String, Integer> wordId = new HashMap<String, Integer>(); List<List<Integer>> edge = new ArrayList<List<Integer>>(); int nodeNum = 0; public int ladderLength(String beginWord, String endWord, List<String> wordList) { for (String word : wordList) { addEdge(word); } addEdge(beginWord); if (!wordId.containsKey(endWord)) { return 0; } int[] dis = new int[nodeNum]; Arrays.fill(dis, Integer.MAX_VALUE); int beginId = wordId.get(beginWord), endId = wordId.get(endWord); dis[beginId] = 0; Queue<Integer> que = new LinkedList<Integer>(); que.offer(beginId); while (!que.isEmpty()) { int x = que.poll(); if (x == endId) { return dis[endId] / 2 + 1; } for (int it : edge.get(x)) { if (dis[it] == Integer.MAX_VALUE) { dis[it] = dis[x] + 1; que.offer(it); } } } return 0; } public void addEdge(String word) { addWord(word); int id1 = wordId.get(word); char[] array = word.toCharArray(); int length = array.length; for (int i = 0; i < length; ++i) { char tmp = array[i]; array[i] = '*'; String newWord = new String(array); addWord(newWord); int id2 = wordId.get(newWord); edge.get(id1).add(id2); edge.get(id2).add(id1); array[i] = tmp; } } public void addWord(String word) { if (!wordId.containsKey(word)) { wordId.put(word, nodeNum++); edge.add(new ArrayList<Integer>()); } } }
golang 解法, 执行用时: 32 ms, 内存消耗: 9.7 MB, 提交时间: 2023-04-22 12:24:37
func ladderLength(beginWord string, endWord string, wordList []string) int { wordId := map[string]int{} graph := [][]int{} addWord := func(word string) int { id, has := wordId[word] if !has { id = len(wordId) wordId[word] = id graph = append(graph, []int{}) } return id } addEdge := func(word string) int { id1 := addWord(word) s := []byte(word) for i, b := range s { s[i] = '*' id2 := addWord(string(s)) graph[id1] = append(graph[id1], id2) graph[id2] = append(graph[id2], id1) s[i] = b } return id1 } for _, word := range wordList { addEdge(word) } beginId := addEdge(beginWord) endId, has := wordId[endWord] if !has { return 0 } const inf int = math.MaxInt64 dist := make([]int, len(wordId)) for i := range dist { dist[i] = inf } dist[beginId] = 0 queue := []int{beginId} for len(queue) > 0 { v := queue[0] queue = queue[1:] if v == endId { return dist[endId]/2 + 1 } for _, w := range graph[v] { if dist[w] == inf { dist[w] = dist[v] + 1 queue = append(queue, w) } } } return 0 }
python3 解法, 执行用时: 124 ms, 内存消耗: 20.5 MB, 提交时间: 2023-04-22 12:24:23
# 广度优先搜索 + 优化建图 class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: def addWord(word: str): if word not in wordId: nonlocal nodeNum wordId[word] = nodeNum nodeNum += 1 def addEdge(word: str): addWord(word) id1 = wordId[word] chars = list(word) for i in range(len(chars)): tmp = chars[i] chars[i] = "*" newWord = "".join(chars) addWord(newWord) id2 = wordId[newWord] edge[id1].append(id2) edge[id2].append(id1) chars[i] = tmp wordId = dict() edge = collections.defaultdict(list) nodeNum = 0 for word in wordList: addEdge(word) addEdge(beginWord) if endWord not in wordId: return 0 dis = [float("inf")] * nodeNum beginId, endId = wordId[beginWord], wordId[endWord] dis[beginId] = 0 que = collections.deque([beginId]) while que: x = que.popleft() if x == endId: return dis[endId] // 2 + 1 for it in edge[x]: if dis[it] == float("inf"): dis[it] = dis[x] + 1 que.append(it) return 0