原题如下:
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出:
[
[“hit”,“hot”,“dot”,“dog”,“cog”],
[“hit”,“hot”,“lot”,“log”,“cog”]
]
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: []
解释: endWord “cog” 不在字典中,所以不存在符合要求的转换序列。
写这题如果对图不太了解的话,将很难做下去,说实话LZ写这题花了很久,又不希望去百度别人的答案或者方法,所以就绞尽脑汁想方法。
所以希望看到这篇博客的人尽量不要去研究代码了。。。我会尽量把思路叙述清楚。
(1)拿到一个beginword,你需要检查从beginWord能不能(经过一次)变成Wordlist【】里面的单词,如果可以,继续下去,否则直接返回
(2)拿到一个endWord,你需要检查wordlist【】里面是否有这个单词,如果有,继续下去,否则直接返回。
(3)通过(1)(2)后,我们就肯定能找到一个进入Wordlist【】的入口first_step 【】(ps::beginWord经过一个char变化的单词(or单词组)),把这些入口,其实就是Wordlist的下标存储起来,至于进入到Wordlist【】之后该怎么办,继续往后走。
(4)接着你还要继续做前导工作,我们需要知道,Wordlist【】内部,每个单词可以转化为的下一个单词是什么!!!(只需要存他的下标就行了),以及我们要知道当前单词,到最终的endword需要转化的最小次数!!!后面可以转化的单词为next_hop【】,当前单词到endword的最小次数为min_distance,把他们封装到一个结构体里Hash_nodes(改造的图)
struct Hash_nodes{
vector<int>next_hop;
int min_distance_to_endPosition;
};
vector<Hash_nodes>hash_wordlist(wordList.size()); 例如 :hash_wordlist【i】.next_hop【】存的是Wordlist【i】单词的所有的后继可转化单词的下标
hash_wordlist【i】.min_distance_to_endPosition表示当前单词到Wordlist的最小转化数
(5)接下来到了最重要的一步,求每个单词到endword的最小步数(或者是说最小转化数),这个将决定,你的时间复杂度的高低!!!对于Wordlist【】内部的单词,他们的下一跳单词,我们当然很容易就求出来了,但是!!!我们只能要那些下一跳单词到endword最近的单词!!!即我们要保证,我们当前要转化为的单词是最好的,最短的,不做无用功(贪心算法的思想!!)
求每个单词的最小转化数(min_distance_to_endPosition):我们要从endword所在位置(endword_position)开始,因为这个点的所在的min_distance=0;而且他的所有的下一个可转化单词(逆向看的话正好一步可以变成endword的单词)所在位置的min_distance一定是1,再往回推,下一个单词的下一个单词的min_distance一定是2
是不是感觉可以用递归来初始化????注意!!!!不要用递归来写这个,因为这个是无向图,很容易造成环路,建议用循环写,用队列或者双vector<>,队列为空的时候就初始化完了。
(6)拿到这个初始化过后的vector<Hash_nodes>hash_wordlist(wordList.size())
我们还要进行删改因为每个单词的后继单词有很多,我们只想要后继单词的min_distance最小(其他的全部删除掉,当然不删除也可以,只不过后续的操作会稍微麻烦一点)
(7)完成了上述的各种前导工作后,可以进行最终的寻找单词接龙过程;
beginWord的接口在(3)中已经求过为first_step 【】,依次选first_step 【i】为入口单词,在hash_wordlist【】内部往后走,最终只要走到endword_position位置了,这个path一定是最短的。
代码如下(一些打印函数是我自己封装的类,已经被我屏蔽掉了,为了方便理解,主调函数内部有一些操作说明,而且我们对Wordlist【】的操作基本上全是对下标的操作!!!最终才转化为string):
struct Hash_nodes{
vector<int>next_hop;
int min_distance_to_endPosition;
};
class Solution {
public:
bool check_one_different(string &a, string &b){
int compare = 0;
for (int i = 0; i <= a.size() - 1; i++){
if (compare >= 2)break;
if (a[i] != b[i])compare++;
}
if (compare == 1) return true;
else return false;
}
int find_string_from_vector(string &s, vector<string>& wordList){
for (int i = 0; i <= wordList.size() - 1; i++){
int j;
for (j = 0; j <= wordList[i].size() - 1; j++){
if (s[j] != wordList[i][j]) break;
}
if (j >= wordList[i].size()) return i;
}
return -1;
}
void chushi_hash_wordlist_minDistance(vector<Hash_nodes>&hash_wordlist, int &end_position){
vector<int>m;
m.push_back(end_position);
while (m.size() != 0){
vector<int>next_m;
for (int i = 0; i <= m.size() - 1; i++){
int now_position = m[i];
if (hash_wordlist[now_position].next_hop.size() > 0){
for (int j = 0; j <= hash_wordlist[now_position].next_hop.size() - 1; j++){
int nextHop = hash_wordlist[now_position].next_hop[j];
if (hash_wordlist[now_position].min_distance_to_endPosition + 1 < hash_wordlist[nextHop].min_distance_to_endPosition){
hash_wordlist[nextHop].min_distance_to_endPosition = hash_wordlist[now_position].min_distance_to_endPosition + 1;
next_m.push_back(nextHop);
}
}
}
}
m = next_m;
}
}
void chushi_hash_wordlist_nextHop(vector<Hash_nodes>&hash_wordlist, int endword_position, vector<string>& wordList){
for (int i = 0; i <= wordList.size() - 1; i++){
//cout << "i==" << i << endl;
for (int j = 0; j <= wordList.size() - 1; j++){
if (i == j)continue;
bool tmp = check_one_different(wordList[j], wordList[i]);
if (tmp) hash_wordlist[i].next_hop.push_back(j); //{cout << "j=="; cout << j << " "; }
}
//cout << endl;
}
for (int i = 0; i <= hash_wordlist.size() - 1; i++)
hash_wordlist[i].min_distance_to_endPosition = INT_MAX;
hash_wordlist[endword_position].min_distance_to_endPosition = 0;
}
vector<int> get_first_step(string beginWord, vector<string>& wordList, vector<Hash_nodes>hash_wordlist){
vector<int>m;
for (int i = 0; i <= wordList.size() - 1; i++){
if (check_one_different(beginWord, wordList[i])) m.push_back(i);
}
int min_distance = INT_MAX;
if (m.size() > 0){
for (int i = 0; i <= m.size() - 1; i++){
int position = m[i];
min_distance = min(min_distance, hash_wordlist[position].min_distance_to_endPosition);
}
vector<int>::iterator p = m.begin();
while (p != m.end()){
int position = (*p);
if (hash_wordlist[position].min_distance_to_endPosition > min_distance) p = m.erase(p);
else p++;
}
}
return m;
}
void erase_hash_wordlist_nextHop(vector<Hash_nodes>&hash_wordlist){
for (int i = 0; i <= hash_wordlist.size() - 1; i++){
if (hash_wordlist[i].min_distance_to_endPosition == 0)continue;
int min_step = INT_MAX;
//下面对hash_wordlist[i].next_hop[]这个数组操作
vector<int>::iterator p = hash_wordlist[i].next_hop.begin();
while (p != hash_wordlist[i].next_hop.end()){
int next_position = (*p);
if (hash_wordlist[next_position].min_distance_to_endPosition < min_step)
min_step = hash_wordlist[next_position].min_distance_to_endPosition;
p++;
}
for (p = hash_wordlist[i].next_hop.begin(); p != hash_wordlist[i].next_hop.end();){
int next_position = (*p);
if (hash_wordlist[next_position].min_distance_to_endPosition > min_step)
p = hash_wordlist[i].next_hop.erase(p);
else p++;
}
}
}
bool digui(int begin_position, int end_position, vector<Hash_nodes>&hash_wordlist,vector<vector<int>>&total,vector<int>&dange){
vector<int>next_hop = hash_wordlist[begin_position].next_hop;
//if (hash_wordlist[begin_position].min_distance_to_endPosition == 1)return true;
if (begin_position==end_position)return true;
for (int i = 0; i <= next_hop.size() - 1; i++){
dange.push_back(next_hop[i]);
bool tmp=digui(next_hop[i], end_position,hash_wordlist,total,dange);
if (tmp)total.push_back(dange);
vector<int>::iterator p = dange.end() - 1; p = dange.erase(p);
}
return false;
}
void from_position_to_string(string beginWord, string endWord, vector<string>& wordList, vector<vector<string>>&m, vector<vector<int>>&total){
for (int i = 0; i <= total.size() - 1; i++){
vector<string>tmp; tmp.push_back(beginWord);
for (int j = 0; j <= total[i].size() - 1; j++){
int position = total[i][j]; tmp.push_back(wordList[position]);
}
//tmp.push_back(endWord);
m.push_back(tmp);
}
}
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
vector<vector<string>>m;
vector<Hash_nodes>hash_wordlist(wordList.size());
int endword_position = find_string_from_vector(endWord, wordList);
if (endword_position == -1)return m;
chushi_hash_wordlist_nextHop(hash_wordlist,endword_position, wordList);
chushi_hash_wordlist_minDistance(hash_wordlist, endword_position);
//上面会得到 所有单词到达 endword的情况
//下面我们要筛选nextHop 因为 他的所有下一跳 我们只要最短的!!!!!!!!
//保证我们的下一跳是最优结果
//print_hash(hash_wordlist);
erase_hash_wordlist_nextHop(hash_wordlist);
//cout << "++++++++++++++++++++++++++++++++++++++++++++++" << endl;
//print_hash(hash_wordlist);
vector<int>first_step = get_first_step(beginWord, wordList, hash_wordlist);
//print.print_onearry(first_step);
if (first_step.size() == 0) return m;
vector<vector<int>>total;
for (int i = 0; i <= first_step.size() - 1; i++){
vector<int>dange;
if (first_step[i] == endword_position) { dange.push_back(endword_position); total.push_back(dange); }
else{
dange.push_back(first_step[i]);
digui(first_step[i], endword_position, hash_wordlist, total, dange);
}
}
if(total.size()>0) from_position_to_string(beginWord, endWord, wordList, m, total);
//print.print_twoarry(m);
return m;
}
};```