题意理解
给出一组单词,问从单词A到单词B的最短路径,相邻的单词只有一个字符不同。
问题分析
用图。BFS,BFS用队列。
思路1,如果从一个单词找它的下一个单词,遍历单词的每个字符,如果将当前字符换成a-z中的一个(最多26次),这样组成的新单词在列表中能找到,说明找到了。为了实现这个思路,将单词列表变换成无序集合,利用无序集合的find找到单词。
思路2,利用队列进行BFS思路,首先,起点如队列,然后,如果队列不空,出队列一个元素,对元素做操作,(中间可能终止遍历),遍历当前元素的相邻元素,依次入队列。
思路3,这题求最短距离长度,所以要对BFS进行改进,改进的方法是初始设置一个层次值为1,然后每次出队列元素时,不是每次出一个,而是用一个循环,每次出掉当前队列中所有的元素,(因为这些元素是一个层次上),当出完所有元素后,就可以增加层次,队列为空,或是找到相应的终单词时,层次数即为最短路径长度。
其他
队列的表示,入队列用push,出队列用pop,不是push_back, pop_front(遇到string会报错)
unordered_set,find元素时间复杂度是o(1).
参考:https://leetcode.com/problems/word-ladder/discuss/40707/C%2B%2B-BFS
链接
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> dict(wordList.begin(), wordList.end()); //vector转化成hash表,便于查找
queue<string> todo;
todo.push(beginWord); //队列用push,不是push_back
int ladder = 1; //设置层次初值
while(!todo.empty()) //队列不空
{
int n = todo.size(); //取出当前层次的范围
for(int i = 0; i < n; i++) //只遍历当前层次的单词
{
string word = todo.front(); //出队列
todo.pop();
if(word == endWord) //处理当前单词
{
return ladder;
}
dict.erase(word); //hash表更新(去掉处理过的单词)
for(int j = 0; j < word.size(); j++) // 对每个字符进行变换
{
char c = word[j];
for(int k = 0; k < 26; k++)
{
word[j] = k + 'a'; //复用单词
if(dict.find(word) != dict.end()) //hash表查找单词
{
//cout << ladder << '\t' << word << endl;
todo.push(word); //找到了就入队列
}
}
word[j] = c; //还原单词
}
}
ladder++; //本层次查询完毕,层次更新
}
return 0;
}