字典 wordList
中从单词 beginWord
_ _ 和 endWord
的 转换序列 是一个按下述规格形成的序列beginWord -> s1 -> s2 -> ... -> sk
:
每一对相邻的单词只差一个字母。
对于 1 <= i <= k
时,每个 si
都在 wordList
中。注意, beginWord
_ _ 不需要在 wordList
中。
sk == endWord
给你两个单词 __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
中的所有字符串 互不相同
方法一:广度优先搜索 + 优化建图 思路
本题要求的是最短转换序列 的长度,看到最短首先想到的就是广度优先搜索 。想到广度优先搜索 自然而然的就能想到图,但是本题并没有直截了当的给出图的模型,因此我们需要把它抽象成图的模型。
我们可以把每个单词都抽象为一个点,如果两个单词可以只改变一个字母进行转换,那么说明他们之间有一条双向边。因此我们只需要把满足转换条件的点相连,就形成了一张图 。
基于该图,我们以 beginWord
为图的起点,以 endWord
为终点进行广度优先搜索 ,寻找 beginWord
到 endWord
的最短路径。
{:width=”60%”}
算法
基于上面的思路我们考虑如何编程实现。
首先为了方便表示,我们先给每一个单词标号,即给每个单词分配一个 id
。创建一个由单词 word
到 id
对应的映射 wordId
,并将 beginWord
与 wordList
中所有的单词都加入这个映射中。之后我们检查 endWord
是否在该映射内,若不存在,则输入无解。我们可以使用哈希表 实现上面的映射关系。
然后我们需要建图,依据朴素的思路,我们可以枚举每一对单词的组合,判断它们是否恰好相差一个字符,以判断这两个单词对应的节点是否能够相连。但是这样效率太低,我们可以优化建图。
具体地,我们可以创建虚拟节点。对于单词 hit
,我们创建三个虚拟节点 *it
、h*t
、hi*
,并让 hit
向这三个虚拟节点分别连一条边即可。如果一个单词能够转化为 hit
,那么该单词必然会连接到这三个虚拟节点之一。对于每一个单词,我们枚举它连接到的虚拟节点,把该单词对应的 id
与这些虚拟节点对应的 id
相连即可。
最后我们将起点加入队列开始广度优先搜索,当搜索到终点时,我们就找到了最短路径的长度。注意因为添加了虚拟节点,所以我们得到的距离为实际最短路径长度的两倍。同时我们并未计算起点对答案的贡献,所以我们应当返回距离的一半再加一的结果。
代码
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 class Solution {public : unordered_map<string, int > wordId; vector<vector<int >> edge; int nodeNum = 0 ; void addWord (string& word) { if (!wordId.count (word)) { wordId[word] = nodeNum++; edge.emplace_back (); } } void addEdge (string& word) { addWord (word); int id1 = wordId[word]; for (char & it : word) { char tmp = it; it = '*' ; addWord (word); int id2 = wordId[word]; edge[id1].push_back (id2); edge[id2].push_back (id1); it = tmp; } } int ladderLength (string beginWord, string endWord, vector<string>& wordList) { for (string& word : wordList) { addEdge (word); } addEdge (beginWord); if (!wordId.count (endWord)) { return 0 ; } vector<int > dis (nodeNum, INT_MAX) ; int beginId = wordId[beginWord], endId = wordId[endWord]; dis[beginId] = 0 ; queue<int > que; que.push (beginId); while (!que.empty ()) { int x = que.front (); que.pop (); if (x == endId) { return dis[endId] / 2 + 1 ; } for (int & it : edge[x]) { if (dis[it] == INT_MAX) { dis[it] = dis[x] + 1 ; que.push (it); } } } return 0 ; } };
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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>()); } } }
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 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
[sol1-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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 }
[sol1-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 struct Trie { int ch[27 ]; int val; } trie[50001 ]; int size, nodeNum;void insert (char * s, int num) { int sSize = strlen (s), add = 0 ; for (int i = 0 ; i < sSize; ++i) { int x = s[i] - '`' ; if (trie[add].ch[x] == 0 ) { trie[add].ch[x] = ++size; memset (trie[size].ch, 0 , sizeof (trie[size].ch)); trie[size].val = -1 ; } add = trie[add].ch[x]; } trie[add].val = num; } int find (char * s) { int sSize = strlen (s), add = 0 ; for (int i = 0 ; i < sSize; ++i) { int x = s[i] - '`' ; if (trie[add].ch[x] == 0 ) { return -1 ; } add = trie[add].ch[x]; } return trie[add].val; } int addWord (char * word) { if (find(word) == -1 ) { insert(word, nodeNum++); } return find(word); } int edge[30001 ][26 ];int edgeSize[30001 ];void addEdge (char * word) { int wordSize = strlen (word), id1 = addWord(word); for (int i = 0 ; i < wordSize; ++i) { char tmp = word[i]; word[i] = '`' ; int id2 = addWord(word); edge[id1][edgeSize[id1]++] = id2; edge[id2][edgeSize[id2]++] = id1; word[i] = tmp; } } int ladderLength (char * beginWord, char * endWord, char ** wordList, int wordListSize) { size = nodeNum = 0 ; memset (trie[size].ch, 0 , sizeof (trie[size].ch)); trie[size].val = -1 ; memset (edgeSize, 0 , sizeof (edgeSize)); for (int i = 0 ; i < wordListSize; ++i) { addEdge(wordList[i]); } addEdge(beginWord); int beginId = find(beginWord), endId = find(endWord); if (endId == -1 ) { return 0 ; } int dis[nodeNum]; memset (dis, -1 , sizeof (dis)); dis[beginId] = 0 ; int que[nodeNum]; int left = 0 , right = 0 ; que[right++] = beginId; while (left < right) { int x = que[left++]; for (int i = 0 ; i < edgeSize[x]; ++i) { if (dis[edge[x][i]] == -1 ) { dis[edge[x][i]] = dis[x] + 1 ; if (edge[x][i] == endId) { return dis[edge[x][i]] / 2 + 1 ; } que[right++] = edge[x][i]; } } } return 0 ; }
复杂度分析
方法二:双向广度优先搜索 思路及解法
根据给定字典构造的图可能会很大,而广度优先搜索的搜索空间大小依赖于每层节点的分支数量。假如每个节点的分支数量相同,搜索空间会随着层数的增长指数级的增加。考虑一个简单的二叉树,每一层都是满二叉树的扩展,节点的数量会以 $2$ 为底数呈指数增长。
如果使用两个同时进行的广搜可以有效地减少搜索空间。一边从 beginWord
开始,另一边从 endWord
开始。我们每次从两边各扩展一层节点,当发现某一时刻两边都访问过同一顶点时就停止搜索。这就是双向广度优先搜索,它可以可观地减少搜索空间大小,从而提高代码运行效率。
{:width=”70%”}
代码
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 class Solution {public : unordered_map<string, int > wordId; vector<vector<int >> edge; int nodeNum = 0 ; void addWord (string& word) { if (!wordId.count (word)) { wordId[word] = nodeNum++; edge.emplace_back (); } } void addEdge (string& word) { addWord (word); int id1 = wordId[word]; for (char & it : word) { char tmp = it; it = '*' ; addWord (word); int id2 = wordId[word]; edge[id1].push_back (id2); edge[id2].push_back (id1); it = tmp; } } int ladderLength (string beginWord, string endWord, vector<string>& wordList) { for (string& word : wordList) { addEdge (word); } addEdge (beginWord); if (!wordId.count (endWord)) { return 0 ; } vector<int > disBegin (nodeNum, INT_MAX) ; int beginId = wordId[beginWord]; disBegin[beginId] = 0 ; queue<int > queBegin; queBegin.push (beginId); vector<int > disEnd (nodeNum, INT_MAX) ; int endId = wordId[endWord]; disEnd[endId] = 0 ; queue<int > queEnd; queEnd.push (endId); while (!queBegin.empty () && !queEnd.empty ()) { int queBeginSize = queBegin.size (); for (int i = 0 ; i < queBeginSize; ++i) { int nodeBegin = queBegin.front (); queBegin.pop (); if (disEnd[nodeBegin] != INT_MAX) { return (disBegin[nodeBegin] + disEnd[nodeBegin]) / 2 + 1 ; } for (int & it : edge[nodeBegin]) { if (disBegin[it] == INT_MAX) { disBegin[it] = disBegin[nodeBegin] + 1 ; queBegin.push (it); } } } int queEndSize = queEnd.size (); for (int i = 0 ; i < queEndSize; ++i) { int nodeEnd = queEnd.front (); queEnd.pop (); if (disBegin[nodeEnd] != INT_MAX) { return (disBegin[nodeEnd] + disEnd[nodeEnd]) / 2 + 1 ; } for (int & it : edge[nodeEnd]) { if (disEnd[it] == INT_MAX) { disEnd[it] = disEnd[nodeEnd] + 1 ; queEnd.push (it); } } } } return 0 ; } };
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 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>()); } } }
[sol2-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 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
[sol2-Golang] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 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 }
[sol2-C] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 struct Trie { int ch[27 ]; int val; } trie[50001 ]; int size, nodeNum;void insert (char * s, int num) { int sSize = strlen (s), add = 0 ; for (int i = 0 ; i < sSize; ++i) { int x = s[i] - '`' ; if (trie[add].ch[x] == 0 ) { trie[add].ch[x] = ++size; memset (trie[size].ch, 0 , sizeof (trie[size].ch)); trie[size].val = -1 ; } add = trie[add].ch[x]; } trie[add].val = num; } int find (char * s) { int sSize = strlen (s), add = 0 ; for (int i = 0 ; i < sSize; ++i) { int x = s[i] - '`' ; if (trie[add].ch[x] == 0 ) { return -1 ; } add = trie[add].ch[x]; } return trie[add].val; } int addWord (char * word) { if (find(word) == -1 ) { insert(word, nodeNum++); } return find(word); } int edge[30001 ][26 ];int edgeSize[30001 ];void addEdge (char * word) { int wordSize = strlen (word), id1 = addWord(word); for (int i = 0 ; i < wordSize; ++i) { char tmp = word[i]; word[i] = '`' ; int id2 = addWord(word); edge[id1][edgeSize[id1]++] = id2; edge[id2][edgeSize[id2]++] = id1; word[i] = tmp; } } int ladderLength (char * beginWord, char * endWord, char ** wordList, int wordListSize) { size = nodeNum = 0 ; memset (trie[size].ch, 0 , sizeof (trie[size].ch)); trie[size].val = -1 ; memset (edgeSize, 0 , sizeof (edgeSize)); for (int i = 0 ; i < wordListSize; ++i) { addEdge(wordList[i]); } addEdge(beginWord); int beginId = find(beginWord), endId = find(endWord); if (endId == -1 ) { return 0 ; } int disBegin[nodeNum]; memset (disBegin, -1 , sizeof (disBegin)); disBegin[beginId] = 0 ; int queBegin[nodeNum]; int leftBegin = 0 , rightBegin = 0 ; queBegin[rightBegin++] = beginId; int disEnd[nodeNum]; memset (disEnd, -1 , sizeof (disEnd)); disEnd[endId] = 0 ; int queEnd[nodeNum]; int leftEnd = 0 , rightEnd = 0 ; queEnd[rightEnd++] = endId; while (leftBegin < rightBegin && leftEnd < rightEnd) { int queBeginSize = rightBegin - leftBegin; for (int i = 0 ; i < queBeginSize; ++i) { int nodeBegin = queBegin[leftBegin++]; if (disEnd[nodeBegin] != -1 ) { return (disBegin[nodeBegin] + disEnd[nodeBegin]) / 2 + 1 ; } for (int j = 0 ; j < edgeSize[nodeBegin]; ++j) { if (disBegin[edge[nodeBegin][j]] == -1 ) { disBegin[edge[nodeBegin][j]] = disBegin[nodeBegin] + 1 ; queBegin[rightBegin++] = edge[nodeBegin][j]; } } } int queEndSize = rightEnd - leftEnd; for (int i = 0 ; i < queEndSize; ++i) { int nodeEnd = queEnd[leftEnd++]; if (disBegin[nodeEnd] != -1 ) { return (disBegin[nodeEnd] + disEnd[nodeEnd]) / 2 + 1 ; } for (int j = 0 ; j < edgeSize[nodeEnd]; ++j) { if (disEnd[edge[nodeEnd][j]] == -1 ) { disEnd[edge[nodeEnd][j]] = disEnd[nodeEnd] + 1 ; queEnd[rightEnd++] = edge[nodeEnd][j]; } } } } return 0 ; }
复杂度分析