最小操作数

来源:互联网 发布:淘宝宝贝删除重新上架 编辑:程序博客网 时间:2024/05/17 09:32

给定一个单词集合Dict,其中每个单词的长度都相同。现从此单词集合Dict中抽取两个单词A、B,我们希望通过若干次操作把单词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"。

class Solution {public:vector<vector<string> > findLadders(string start, string end,set<string>& dict) {vector<vector<string> > result, result_temp;if (dict.erase(start) == 1 && dict.erase(end) == 1) {//为当前方向上所有点与其下一结点的配对map<string, vector<string> > kids_from_start;map<string, vector<string> > kids_from_end;//开始方向经过的点集set<string> reach_start;reach_start.insert(start);//终点方向经过的点集set<string> reach_end;reach_end.insert(end);set<string> meet;//BFS直到相交while (meet.empty() && !reach_start.empty() && !reach_end.empty()) {if (reach_start.size() < reach_end.size()) {//从开始方向搜索子结点和其分支search_next_reach(reach_start, reach_end, meet,kids_from_start, dict);/*cout << "start "; printMap(kids_from_start);*/} else {search_next_reach(reach_end, reach_start, meet,kids_from_end, dict);/*cout << "end "; printMap(kids_from_end);*/}//printset(meet);}if (!meet.empty()) {//由相遇点拓展可走路径数for (set<string>::iterator it = meet.begin(); it != meet.end();++it) {//参数1是空间,参数2是值vector<string> words(1, *it);result.push_back(words);}//由相遇点向起点拓展分支walk(result, kids_from_start);/*printvv(result); printMap(kids_from_start);*/for (size_t i = 0; i < result.size(); ++i) {reverse(result[i].begin(), result[i].end());}walk(result, kids_from_end);/*printvv(result); printMap(kids_from_end);*/}}return result;}private:/*reach为该方向已经经过的点集, * other_reach为反方向, * meet为两个方向点集相交点集, * path为当前方向上所有点与其下一结点的配对,(下一元素:{当前元素}) * dict为字典集合*/void search_next_reach(set<string>& reach, const set<string>& other_reach,set<string>& meet, map<string, vector<string> >& path,set<string>& dict) {//reach必须从端点开始遍历,所以必须重新添加,不然会重复set<string> temp;reach.swap(temp);/*对该方向已出现的元素匹配下一元素 * 匹配方案: * 尝试依次改变指定位置上的元素来匹配*/for (set<string>::iterator it = temp.begin(); it != temp.end(); ++it) {string s = *it;for (size_t i = 0; i < s.length(); ++i) {char back = s[i];for (s[i] = 'a'; s[i] <= 'z'; ++s[i]) {if (s[i] != back) {//已出现在当前点集if (reach.count(s) == 1) {path[s].push_back(*it);} else if (dict.erase(s) == 1) {//存在于字典中,删除后加入点集path[s].push_back(*it);reach.insert(s);} else if (other_reach.count(s) == 1) {//存在于相反方向集合,说明点集相交path[s].push_back(*it);reach.insert(s);meet.insert(s);}}}s[i] = back;}}}void walk(vector<vector<string> >& all_path,map<string, vector<string> > kids) {vector<vector<string> > temp;//到达起止点则为空while (!kids[all_path.back().back()].empty()) {//每个路径的结尾元素可以对应多个子元素,则拼接路径有多条,所以必须先清空再添加all_path.swap(temp);all_path.clear();for (vector<vector<string> >::iterator it = temp.begin();it != temp.end(); ++it) {vector<string>& one_path = *it;//取得当前路径尾元素的下一元素集合vector<string>& p = kids[one_path.back()];//将下一元素集合的每一元素与尾元素分别拼接,存为新路径for (size_t i = 0; i < p.size(); ++i) {all_path.push_back(one_path);all_path.back().push_back(p[i]);}}}}};


0 0
原创粉丝点击