题目来源
题目描述
int ladderLength(std::string start, std::string end, std::vector<std::string> &dict){
}
题目解析
题意
从起点词出发,每次变一个字母,变换 n 次,变成终点词,希望 n 尽量小。
思路
- 我们需要找出邻接关系,比如hit的转换词是it、ht、hi*形式,看看这样的新词是否在单词表里,如果存在,就找到了一个下一层的转换词。
- 同时,要避免重复访问,hot->dot->hot,别这样变回来,徒增转换的次数。所以,确定了下一个转换词,就把它从单词表中删除。
- 下一层的转换词可能有多个,都要考察,哪一条转换路径先遇到终点词,它就最短。
整理一下:
- 把单词看作结点,由一个结点带出下一层的邻接点,用BFS去做。
- 维护一个队列,让起点词入列,level 为 1,然后出列考察。
- 将逐个字符变成26字母之一,看看是否在单词表,如果在,该新词为下一层的转换词。
- 将它入列,它的 level +1,并从单词表中删去这个词。
- 出列、入列…重复,当出列的单词和终点词相同,就遇到了终点词,返回它的 level。
- 当队列为空时,代表考察完所有词,始终没有遇到终点词,没有路径通往终点。
实现:
class Solution {
public:
int ladderLength(std::string beginWord, std::string endWord, std::vector<std::string> &wordList){
if(beginWord.size() == 0 || endWord.size() == 0 || wordList.size() == 0)
return 0;
int iWordLen = (int)beginWord.size();
unordered_set<string> hashdata;
for (auto it : wordList)
hashdata.insert(it);
queue<string> qdata;
qdata.push(beginWord);
int level = 1;
while(!qdata.empty()){//BFS
level++;
int isize = qdata.size();
for(int i = 0 ; i < isize ; ++i){
string head = qdata.front();
qdata.pop();
for(int j = 0; j < iWordLen; ++j){// 这个单词的每个字符都遍历一遍字母表
string temp = head;
for(char ch = 'a'; ch <= 'z'; ++ch){
temp[j] = ch;
auto it = hashdata.find(temp);
if (it != hashdata.end()){
if(temp == endWord) return level;
qdata.push(temp);
hashdata.erase(it); //加入队列之后删掉单词池的元素,防止回退
}
}
}
}
}
return 0;
}
};
思路
(1)start不一定在dict中,所以将start加入到dict中
(2)为dict中的每一个单词生成一个邻居表:
- 所谓邻居,就是任何两个字符串只有一个位置不一样
- 一个单词会有多个邻居,所以key = 每一个单词,value:单词对应的邻居
(3)以start作为起点,宽度优先遍历,直到找到end
实现
class Solution {
// 应该根据具体数据状况决定用什么来找邻居
// 1)如果字符串长度比较短,字符串数量比较多,以下方法适合
// 2)如果字符串长度比较长,字符串数量比较少,以下方法不适合
std::vector<std::string> getNext(std::string word, std::set<std::string> dict){
std::vector<std::string> ans;
for (int i = 0; i < word.size(); ++i) {
for (char ch = 'a'; ch < 'z'; ++ch) {
if(word[i] != 'a'){
char tmp = word[i];
word[i] = ch;
if(dict.count(word)){
ans.push_back(word);
}
word[i] = tmp;
}
}
}
return ans;
}
std::map<std::string, std::vector<std::string>> getNexts(std::vector<std::string> words){
std::set<std::string> dict(words.begin(), words.end());
std::map<std::string, std::vector<std::string>> nexts;
for (const auto & word : words) {
nexts[word] = getNext(word, dict);
}
return nexts;
}
public:
int ladderLength(std::string start, std::string end, std::vector<std::string> &dict){
dict.push_back(start);
auto nexts = getNexts(dict);
std::map<std::string, int> distanceMap;
distanceMap[start] = 1;
std::set<std::string> set;
set.emplace(start);
std::queue<std::string> queue;
queue.push(start);
while (!queue.empty()){
auto cur = queue.front(); queue.pop();
int dis = distanceMap[cur];
for(auto next : nexts[cur]){
if(next == end){
return dis + 1;
}
if(!set.count(next)){
set.emplace(next);
queue.emplace(next);
distanceMap[next] = dis + 1;
}
}
}
return 0;
}
};