题目如下:
给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列
比如:
- 每次只能改变一个字母。
- 变换过程中的中间单词必须在字典中出现。
注意事项
- 所有单词具有相同的长度。
- 所有单词都只包含小写字母。
注意事项
- 所有单词具有相同的长度。
- 所有单词都只包含小写字母。
样例
给出数据如下:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
返回
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
解题思路:
这题目在题意上本人有一点疑惑,因为题意表示每一次只改变一个字母,但没说明在哪种前提下。在这里可以理解成“只要其他字母相同即可”跟“其他字母跟所在位置相同”。例如“dig”,“gad”这两个单词(d,g相同,i,a不同)也是符合题意的。虽然如此,但本人还是以最大困难的前提“只要其他字母相同即可“来解题。从而可以兼顾两种前提。
解题过程中,需要注意以下几点:
1:既然选择了字母位置无关性的前提,那么该如何判断“只改变一个字母”。
【字母位置的无关性前提下,使用标记法显然会事半功倍,以前的博文中早有提及,合理使用bitset能省下不少麻烦。并且,单词(对于重复元素,出现偶数次记0,奇数次记1)之间如果只改变了一个字母,那么标记后产生的数字相异或也就会剩下两个1,这里使用bitset的count方法即可。】
2:由于需要转化成图,该使用何种方法插入节点。
【既然判断已完成,那么遍历上本人就以深度优先来遍历建图,当然其中还有一些需要注意的地方,不难思考因此简略。】
3:建图后,怎么寻找最短路径。
【由于路径存在重复元素的输出,使用回溯法明显比使用深度或宽度优先遍历更加明智,至于是否最短路径,比较size即可】
思路结构定义如下:
typedef struct NNODE
{
int count = 0; int index = 0; vector<NNODE *>child;
NNODE(int c, int i) { count = c; index = i; }
NNODE() {}
~NNODE() { for (NNODE*n : child) { if (n)delete n; } }
}NNODE;
思路代码实现如下:
int part_1(char *c)
{
int m = 0;
while (*c){
if (m&(1 << (*c - 'a')))
m ^= 1 << (*c - 'a');
else
m |= 1 << (*c - 'a');
c++;
}return m;
}
bool part_2(NNODE *root,pair<int,int> &in)
{
NNODE *temp_; bool l = false;
stack<NNODE *>stack_;
stack_.push(root);
while (!stack_.empty()){
temp_ = stack_.top(); stack_.pop();
if (in.first == temp_->count)continue;
bitset<32>bitset_(in.first^temp_->count);
for (NNODE * n : temp_->child)
stack_.push(n);
if (bitset_.count() == 2){
NNODE *in_ = new NNODE(in.first, in.second);
temp_->child.push_back(in_);
l = true;
}
}
return l;
}
void Method(char *start, char *end, vector<char *> &dict, vector<vector<char *>> &result)
{
dict.push_back(end); int m = 1;
deque<pair<int, int>> deque_;
pair<int, int> ptemp_;
vector<char *> vtemp_;
NNODE *root_ = new NNODE(part_1(start), -1), *child_ = 0, *temp_ = 0;
for (int i = 0; i < (int)dict.size(); ++i)
{
ptemp_ = make_pair(part_1(dict[i]), i);
if (!part_2(root_, ptemp_)){
deque_.push_back(ptemp_); continue;
}
while (!deque_.empty() && m){
m = 0; int s = deque_.size();
for (int i = 0; i < s; ++i){
ptemp_ = deque_.front(); deque_.pop_front();
if (part_2(root_, ptemp_))
m++;
else
deque_.push_back(ptemp_);
}
}
}
while (!deque_.empty()){
int i = deque_.back().second;
deque_.pop_back();
if (dict[i] == end){
vtemp_.push_back("none"), result.push_back(vtemp_); return;
}
}
child_ = root_; m = 2147483647;
while (true){
vtemp_.push_back(child_->index == -1 ? start : dict[child_->index]);
int i = child_->child.size();
bool l = child_->index == -1 ? false : dict[child_->index] == end;
if (i == 0 || l){
if (l) if (m >= (int)vtemp_.size())result.push_back(vtemp_), m = vtemp_.size();
vtemp_.clear();
child_ = root_;
if (temp_)
delete temp_->child[temp_->child.size() - 1],
temp_->child.pop_back(),
temp_ = 0;
else if (i == 0) break;
continue;
}
if (i > 1)
temp_ = child_,
child_ = child_->child[i - 1];
else child_ = child_->child[0];
}
delete root_;
}
注意事项
- 所有单词具有相同的长度。
- 所有单词都只包含小写字母。