Given two words (beginWord and endWord), and a dictionary, find the length of shortest transformation sequence from beginWord to endWord, 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.
给定任意两个单词,从一个单词(beginword)开始,每次变化一个字母,问最少需要多少次才能变化到另外一个单词(endword)。
思路很简单,从beginword开始,遍历unordered_map<string> dict ,在里面找到与beginword相差1的单词,将该单词加入队列
每次取队列头结点,对该节点中的单词,如果单词和endword相差1,则返回该节点的层数+1,
否则,在dict中找到与该节点的单词相差1的单词,并且这个单词没有加入到队列过,然后将单词加入队列。
这种方法很直观,小数据量会很快得出结果,但是在大数据量时会非常慢。12K的数据量,跑了5,6秒,简直不能忍。
刚开始以为是入队出队造成字符串频繁拷贝的开销,于是在这个地方进行优化,搞了半天没效果。
于是输出了一下遍历dict元素的次数,发现12K的数据,遍历的次数有1000多万次,难怪会超时。
换个思路,每次把beginword变化一个单词,总共可以变化成多少种?
对于字符串“a”,有25种,对于字符串“ab”,有多少种呢?一直以为是25*25种,后来一想是25*strlen("ab"),共50种
这样,只需要遍历50次,相比遍历整个dict(1万多次),效率实在高太多了。
完整AC代码:
class node{
public:
const string str;
int level;
node(const string& s, int lev):str(s), level(lev){}
};
bool isDiffByOne(const string& s, const string& t)
{
int count = 0;
for(unsigned int i = 0;i<s.size();i++){
if(s[i] != t[i]){
count++;
}
if(count >= 2){
return false;
}
}
return true;
}
class Solution {
public:
void foreach(node& nd, queue<node>& q,
unordered_set<string>& wordDict,
unordered_set<string>& hasvisited)
{
for(int i = 0;i<nd.str.size();i++){
for(int j = 0;j < 26;j++){
string tmp = nd.str;
tmp[i] = 'a' + j;
if(tmp != nd.str && wordDict.find(tmp) != wordDict.end()
&& hasvisited.find(tmp) == wordDict.end()){
q.push(node(tmp, nd.level + 1));
hasvisited.insert(tmp);
}
}
}
}
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
if(beginWord == endWord) return 1;
unordered_set<string> hasvisited;
queue<node> q;
q.push(node(beginWord, 1));
while(!q.empty()){
node nd = q.front();
q.pop();
if(isDiffByOne(nd.str, endWord)){
return nd.level + 1;
}
foreach(nd, q, wordDict, hasvisited);
}
return 0;
}
};