原題:
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" ->
"dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
剛看這題可能沒有思路,但是把變換過程在紙上畫畫之後就明白怎麼做了。以下是題目的抽象圖。
即從圖上找尋從起始節點到目標節點的最短路徑問題。這是圖的遍歷問題,使用的方法無非BFS和DFS,要找最短路徑,DFS只會一路到底,無疑BFS最合適。用BFS遍歷圖,一旦碰到目標節點即退出,此時路徑即是最短路徑。
注意:
(1)BFS搜索應該用隊列來模擬;
(2)應該用一個數組類型的數據結構來記錄已被遍歷的節點,爲求速度,可以使用unordered_set或set(竟然會超時);
(3)遍歷時,應該將與某個節點相鄰的未訪問節點push進隊列中,但怎麼知道兩個節點相鄰?一個個搜索比較會超時,網上有一種很巧妙的方法,即依次將節點string的第i位變換(26次)然後在字典中查找變換後的節點是否在字典中(用的unordered_set數據結構,查找時間爲常數),相同的話push進隊列;
(4)節點不僅要記錄string,還要記錄其在遍歷中是第幾步,應該用一個struct封裝;
好了上代碼:
class Solution {
public:
struct Node{
string str;
int count;
Node(string s, int n) :str(s), count(n){}
};
public:
int ladderLength(string start, string end, unordered_set<string> &dict)
{
if (start == end)
return 1;
if (isNeibours(start, end))
return 2;
visited.clear();
while (!que.empty())
que.pop();
que.push(Node(start, 1));
int res = 0;
while (!que.empty())
{
Node NowNode(que.front());
if (isNeibours(NowNode.str, end))
{
res = NowNode.count + 1;
break;
}
que.pop();
for (int i = 0; i < NowNode.str.size(); ++i)
{
for (int j = 0; j < 26; ++j)
{
string temp = NowNode.str;
temp[i] = 'a' + j;
if (temp != NowNode.str && dict.find(temp) != dict.end() && visited.find(temp) == visited.end())
{
que.push(Node(temp,NowNode.count+1));
visited.insert(temp);
}
}
}
}
return res;
}
private:
bool isNeibours(string s1, string s2)
{
int count = 0;
for (int i = 0; i < s1.size(); ++i)
{
if (s1[i] != s2[i])
++count;
if (count > 1)
return false;
}
return true;
}
private:
unordered_set<string> visited;
queue<Node> que;
};