題目描述
給定兩個單詞(beginWord 和 endWord)和一個字典,找到從 beginWord 到 endWord 的最短轉換序列的長度。轉換需遵循如下規則:
- 每次轉換隻能改變一個字母。
- 轉換過程中的中間單詞必須是字典中的單詞。
說明
- 如果不存在這樣的轉換序列,返回 0。
- 所有單詞具有相同的長度。
- 所有單詞只由小寫字母組成。
- 字典中不存在重複的單詞。
- 你可以假設 beginWord 和 endWord 是非空的,且二者不相同。
示例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" 不在字典中,所以無法進行轉換。
思路
兩端搜索。本題是需要從beginWord
轉換爲endWord
。上一份筆記嚴格按照這個要求,進行轉換,結果爲88ms
。
本條筆記採用兩端搜索對上一份筆記進行了優化。兩端搜索也就是說:“一頭從beginWord
轉換爲endWord
,另外一頭從endWord
轉換爲beginWord
。”爲什麼要這麼做呢?有什麼意義呢?
舉個例子:
-
假設從
beginWord
轉換爲endWord
,存在於字典中的,(第一個)中間結果有30
個。 -
而,從
endWord
轉換爲beginWord
,存在於字典中的,(第一個)中間結果只有2
個。 -
那麼,很顯然。從
endWord
開始會更快。所以,每次都從個數少的那塊開始替換一位。
因此,我們每次都從中間結果少的那一端出發,這樣就能剪枝掉很多不必要的搜索過程。
實現1
bool isOneChar(string& word1, string& word2) {
if (word1.length() != word2.length())
{
return false;
}
int count = 0;
int len = word1.length();
for (int i = 0; i < len; i++)
{
if (word1[i] != word2[i])
{
count++;
}
}
return count == 1;
}
void getResultWord(string beginWord, string endWord, vector<string>& wordList, vector<string>& vecList, int& minLen){
if (beginWord == endWord)
{
if (vecList.size() < minLen)
{
minLen = vecList.size();
}
} else if (isOneChar(beginWord, endWord))
{
vecList.push_back(endWord);
if (vecList.size() < minLen)
{
minLen = vecList.size();
}
} else {
int startCount = 0;
int endCount = 0;
for (int i = 0; i < wordList.size(); i++)
{
if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end())
{
if(isOneChar(beginWord, wordList[i])) {
startCount++;
}
if (isOneChar(endWord, wordList[i]))
{
endCount++;
}
}
}
if (startCount <= endCount)
{
for (int i = 0; i < wordList.size(); i++)
{
if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end() && isOneChar(beginWord, wordList[i])) {
vecList.push_back(wordList[i]);
getResultWord(wordList[i], endWord, wordList, vecList, minLen);
vecList.pop_back();
}
}
} else {
for (int i = 0; i < wordList.size(); i++)
{
if (find(vecList.begin(), vecList.end(), wordList[i]) == vecList.end() && isOneChar(endWord, wordList[i])) {
vecList.push_back(endWord);
getResultWord(beginWord, wordList[i], wordList, vecList, minLen);
vecList.pop_back();
}
}
}
}
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
if (find(wordList.begin(), wordList.end(), endWord) == wordList.end())
{
return 0;
}
vector<string> vecList;
int minLen = INT_MAX;
vecList.push_back(beginWord);
getResultWord(beginWord, endWord, wordList, vecList, minLen);
if (minLen == INT_MAX)
{
minLen = 0;
}
return minLen;
}
實現2
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> wordDict(wordList.begin(), wordList.end());
if (wordDict.find(endWord) == wordDict.end()){
return 0;
}
unordered_set<string> beginSet{beginWord};
unordered_set<string> endSet{endWord};
int step = 1;
for (; !beginSet.empty();){
unordered_set<string> tempSet;
++step;
for (auto s : beginSet) {
wordDict.erase(s);
}
for (auto s : beginSet) {
for (int i = 0; i < s.size(); ++i){
string str = s;
for (char c = 'a'; c <= 'z'; ++c){
str[i] = c;
if (wordDict.find(str) == wordDict.end()){
continue;
}
if (endSet.find(str) != endSet.end()){
return step;
}
tempSet.insert(str);
}
}
}
if (tempSet.size() < endSet.size()){
beginSet = tempSet;
} else {
beginSet = endSet;
endSet = tempSet;
}
}
return 0;
}