题目
给了A、B两个单词和一个单词集合Dict,每个的长度都相同。我们希望通过若干次操作把单词A变成单词B,每次操作可以改变单词中的一个字母,同时,新产生的单词必须是在给定的单词集合Dict中。求所有行得通步数最少的修改方法。
举个例子如下:
Given:
A = "hit"
B = "cog"
Dict = ["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
即把字符串A = "hit"转变成字符串B = "cog",有以下两种可能:
- "hit" -> "hot" -> "dot" -> "dog" -> "cog";
- "hit" -> "hot" -> "lot" -> "log" ->"cog"。
程序分析
利用二叉链表表示法将各字符串按照相差字符个数组织起来,叶子结点是目标串,建立二叉链表时记录从根结点到叶子结点的最小跳数,如果在建立过程中超个过最小跳数,则终止这条路径。
建立完二叉链表后,深度优先遍历记录节点数即可。
结构图:
黄色线表示结点的父亲结点。
测试例子中的树形图为:
黑色虚线表示这条路径的长度超过了最短的路径,只自动丢弃即可,如图从hit-->cog最长为5跳,则hit->hot->dot->lot->log...超过了5跳了,弃之
代码:
#include <string>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
typedef struct __Tree
{
string str;
struct __Tree *parent;
struct __Tree *sibling;
struct __Tree *child;
}Tree;
class Solution
{
private:
string *m_str;
Tree m_head;
int m_n;
public:
bool compareStr(string &s1, string &s2)
{
int count = 0;
int l = s1.length();
for(int i = 0; i < l; i++)
{
if(s1[i] != s2[i])
{
count++;
if(count > 1)
{
break;
}
}
}
return (count == 1) ? true : false;
}
void createTree(string &start, string &end, set<string>& dict)
{
set<string>::iterator iter;
string str;
bool flag = false;
Tree *p;
m_head.str = start;
m_head.parent = NULL;
m_head.sibling = NULL;
m_n = 100000;
//孩子节点生成过程
for(iter = dict.begin(); iter != dict.end(); iter++)
{
str = *iter;
if(compareStr(str, m_head.str))//与当前节点比较
{
p = new Tree;
p->str = str;
p->parent = &m_head;
m_head.child = p;
createNode(*p, 2, end, dict);
break;
}
}
if(iter == dict.end())//如果没有差一个字符的,判断是否与end一样
{
if(compareStr(end, m_head.str))
{
p = new Tree;
p->str = end;
p->parent = &m_head;
p->sibling = NULL;//不用向下比较了,之后的一定比当前的长
m_head.child = p;
m_n = 2;//记录最小长度
}
else
{
m_head.child = NULL;
}
}
}
void createNode(Tree &node, int n, string &end, set<string>& dict)
{
set<string>::iterator iter;
string str;
bool flag = false;
Tree *p;
node.child = NULL;
node.sibling = NULL;
//剪枝,大小最小长度,去除
if(n > m_n)
{
return;
}
if(compareStr(end, node.str))
{
p = new Tree;
p->str = end;//表示结束
p->parent = &node;
p->sibling = NULL;//不用向下比较了,之后的一定比当前的长
p->child = NULL;
node.child = p;
if(n < m_n)
{
m_n = n;//记录最小长度
}
// return;
}
else
{
//孩子节点生成过程
for(iter = dict.begin(); iter != dict.end(); iter++)
{
str = *iter;
if(compareStr(str, node.str))//与当前节点比较
{
//兄弟节点比较,找到还没有用过的
p = node.parent->child;
while(p)
{
if(str.compare(p->str) == 0)
{
flag = true;
break;
}
p = p->sibling;
}
if(flag == true)
{
flag = false;
continue;
}
//父亲节点比较
p = node.parent;
while(p)
{
if(iter->compare(p->str) == 0)
{
flag = true;//节点之前已经存在
break;
}
p = p->parent;
}
if(flag == true)
{
flag = false;
continue;
}
p = new Tree;
p->str = str;
p->parent = &node;
node.child = p;
createNode(*p, n + 1, end, dict);
break;
}
}
if(iter == dict.end())//如果没有符合条件的,置空
{
node.child = NULL;
}
}
//兄弟节点生成过程
flag = false;
for(iter = dict.begin(); iter != dict.end(); iter++)
{
str = *iter;
if(compareStr(str, node.parent->str))//与父亲节点比较,且与当前节点不同的节点
{
//兄弟节点比较,找到还没有用过的
p = node.parent->child;
while(p)
{
if(str.compare(p->str) == 0)
{
flag = true;
break;
}
p = p->sibling;
}
if(flag == true)
{
flag = false;
continue;
}
//父亲节点比较,找到还没有用过的
p = node.parent->parent;
while(p)
{
if(iter->compare(p->str) == 0)
{
flag = true;//节点之前已经存在
break;
}
p = p->parent;
}
if(flag == true)
{
flag = false;
continue;
}
p = new Tree;
p->str = str;
p->parent = node.parent;
node.sibling = p;
createNode(*p, n, end, dict);
break;
}
}
if(iter == dict.end())//如果没有符合条件的,置空
{
node.sibling = NULL;
}
}
void DFS(Tree *root, int n, vector<string> &vec, vector<vector<string>> &vvec, string &end)
{
vector<string> *p;
if(root == NULL)
{
return;
}
if(n > m_n)//超过最小长度的,去除掉
{
return;
}
cout << "第" << n + 1 << "层:" << root->str<<endl;
vec.insert(vec.begin() + n, root->str);
if(root->str.compare(end) == 0)
{
p = new vector<string>;
for(vector<string>::iterator iter = vec.begin(); iter < vec.end(); iter++)
{
p->push_back(*iter);
}
vvec.push_back(*p);
}
DFS(root->child, n + 1, vec, vvec, end);
//去除前一个过程中的后面部分
for(int i = vec.size(); i > n; i--)
{
vec.pop_back();
}
DFS(root->sibling, n, vec, vvec, end);
}
vector<vector<string>> findLadders(string start, string end, set<string>& dict)
{
vector<string> vec;
vector<vector<string>> vvec;
if(start == end)
{
return vvec;
}
else if(compareStr(start, end))
{
vec.push_back(start);
vec.push_back(end);
vvec.push_back(vec);
}
else
{
createTree(start, end, dict);
DFS(&m_head, 0, vec, vvec, end);
}
return vvec;
}
};
测试
int main()
{
Solution aa;
// string start("a2b");
string start("hit");
vector<vector<string>> vec;
vector<string>a;
// string end("bmn");
string end("cog");
set<string> set1;
set1.insert("hot");
set1.insert("dot");
set1.insert("dog");
set1.insert("lot");
set1.insert("log");
//set1.insert("amn");
//set1.insert("a2n");
//set1.insert("b2b");
//set1.insert("bhb");
//set1.insert("b2n");
//set1.insert("ahn");
vec = aa.findLadders(start, end, set1);
for(vector<vector<string>>::iterator vviter = vec.begin(); vviter < vec.end(); vviter++)
{
cout << *vviter->begin();
for(vector<string>::iterator iter = vviter->begin() + 1; iter < vviter->end(); iter++)
{
cout << "->" <<*iter;
}
cout << endl;
}
return 0;
}
结果:int main()
{
Solution aa;
string start("a2b");
// string start("hit");
vector<vector<string>> vec;
vector<string>a;
string end("bmn");
// string end("cog");
set<string> set1;
//set1.insert("hot");
//set1.insert("dot");
//set1.insert("dog");
//set1.insert("lot");
//set1.insert("log");
set1.insert("amn");
set1.insert("a2n");
set1.insert("b2b");
set1.insert("bhb");
set1.insert("b2n");
set1.insert("ahn");
vec = aa.findLadders(start, end, set1);
for(vector<vector<string>>::iterator vviter = vec.begin(); vviter < vec.end(); vviter++)
{
cout << *vviter->begin();
for(vector<string>::iterator iter = vviter->begin() + 1; iter < vviter->end(); iter++)
{
cout << "->" <<*iter;
}
cout << endl;
}
return 0;
}
结果: