一、題目
字典 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 中的所有字元串 互不相同
二、思路
- 可以把每個單詞都看作一個點,至于是否有邊,那麼就看能否進行轉化即相差一個字母,若能轉化即有邊,對所有單詞進行建圖,最後bfs求一次最短距離即可。 O(N2)
- 我們簡化建圖,上面的方法一個頂點最短有N-1條邊,我們可以為每個單詞增加虛拟節點,如hit即增加3個虛拟節點*it,h*t,hi*,讓hit與3個虛拟節點相連接配接即可,若有單詞能夠到達hit那麼必然與3個虛拟節點有邊。于是每個單詞最多有C條邊,C為單詞的長度,複雜度O(NCC) N*C是頂點個數,C是邊數。
- 雙向BFS:來減少搜尋樹的長度,從起點和終點同時開始搜尋,當某個節點處相遇即是答案。
三、代碼
class Solution {
public:
int minv = 1e6;
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
int n = wordList.size();
vector<vector<int>> g(n + 1);
// 對每個單詞進行建邊
wordList.push_back(beginWord);
int end = -1;
for (int i = 0; i <= n; i++) {
if (wordList[i] == endWord) end = i;
for (int j = i + 1; j <= n; j++) {
if (ok(i, j, wordList)) {
g[i].push_back(j);
g[j].push_back(i);
}
}
}
if (end == -1) return 0; //不存在
// 從編号n開始搜尋
return bfs(n, 1, g, end);
}
int bfs(int n, int t, vector<vector<int>>& g, int end) {
vector<bool> v(n + 1);
queue<int> q;
int step = 0;
q.push(n);
v[n] = true;
while (!q.empty()) {
int size = q.size();
step++;
for (int t = 0; t < size; t++) {
int u = q.front(); q.pop();
for (int i = 0; i < g[u].size(); i++) {
int nv = g[u][i];
if (!v[nv]) {
v[nv] = true;
q.push(nv);
if (nv == end) return step + 1;
}
}
}
}
return 0;
}
bool ok(int i, int j, vector<string>& wordList) {
int cnt = 0;
for (int k = 0; k < wordList[i].size(); k++) {
if (wordList[i][k] != wordList[j][k]) cnt++;
}
return cnt <= 1;
}
};
class Solution {
public:
unordered_map<string, int> mp;
int node_num = 0;
vector<vector<int>> edge;
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//建構虛拟節點和邊
wordList.push_back(beginWord);
for (string& s: wordList) addEdge(s);
//bfs求最短距離
if (!mp.count(endWord)) return 0;
int end = mp[endWord];
queue<int> q;
q.push(mp[beginWord]);
vector<int> dis(node_num, 1e6);
dis[mp[beginWord]] = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
if (dis[v] > dis[u] + 1) {
dis[v] = dis[u] + 1;
q.push(v);
if (v == end) return dis[v] / 2 + 1;
}
}
}
return 0;
}
void addNode(string& s) {
if (!mp.count(s)) {
mp[s] = node_num++;
//edge.emplace_back();//增加一個vetor<int>
edge.push_back(vector<int>(0));
}
}
void addEdge(string& s) {
addNode(s);
int idx = mp[s];
//建立c個虛拟結點
for (char& c: s) {
char t = c;
c = '*';
addNode(s);
int idx2 = mp[s];
edge[idx].push_back(idx2);
edge[idx2].push_back(idx);
c = t; //還原字元
}
}
};
- 雙向BFS
class Solution {
public:
unordered_map<string, int> mp;
int node_num = 0;
vector<vector<int>> edge;
int MAXSIZE = 1e6;
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//建構虛拟節點和邊
wordList.push_back(beginWord);
for (string& s: wordList) addEdge(s);
//bfs求最短距離
if (!mp.count(endWord)) return 0;
int end = mp[endWord];
queue<int> q, q_end;
q.push(mp[beginWord]);
q_end.push(end);
vector<int> dis(node_num, MAXSIZE);
vector<int> dis_end(node_num, MAXSIZE);
dis[mp[beginWord]] = 0;
dis_end[end] = 0;
while (!q.empty() && !q_end.empty()) {
int size = q.size();
for (int t = 0; t < size; t++) {
int u = q.front(); q.pop();
for (int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
if (dis[v] > dis[u] + 1) {
dis[v] = dis[u] + 1;
q.push(v);
if (dis_end[v] != MAXSIZE) return (dis[v] + dis_end[v]) / 2 + 1;
}
}
}
size = q_end.size();
for (int t = 0; t < size; t++) {
int u = q_end.front(); q_end.pop();
for (int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
if (dis_end[v] > dis_end[u] + 1) {
dis_end[v] = dis_end[u] + 1;
q_end.push(v);
if (dis[v] != MAXSIZE) return (dis[v] + dis_end[v]) / 2 + 1;
}
}
}
}
return 0;
}
void addNode(string& s) {
if (!mp.count(s)) {
mp[s] = node_num++;
//edge.emplace_back();//增加一個vetor<int>
edge.push_back(vector<int>(0));
}
}
void addEdge(string& s) {
addNode(s);
int idx = mp[s];
//建立c個虛拟結點
for (char& c: s) {
char t = c;
c = '*';
addNode(s);
int idx2 = mp[s];
edge[idx].push_back(idx2);
edge[idx2].push_back(idx);
c = t; //還原字元
}
}
};