【庞果英雄会】最小操作数
来源:互联网 发布:为知笔记怎么分享 编辑:程序博客网 时间:2024/04/30 14:36
给了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"。
我的思路如下:
广度优先方式建立多叉树(类似多叉树)。从开始给的字符开始,从字典中找相差一个字母的所有集合,都为开始字符的孩子节点,并将这些节点放到一个列表list中。然后对列表list中的每一个节点N,继续找相差一个字母的所有集合(不包含已经在树上,且深度低于当前处理层的节点),做为N的孩子节点。这样,以广度优先的方式来建立多叉树。最后遇到了单词B,把这一层处理完,就可以从树上倒推得到变化过程了(可行的变化可能有多个)。
根据例子中所给的字典建立多叉树的过程(先要将字符B加入到字典中):
需要注意的是:
1 树是逐层建立起来的,也就是广度优先,而不是深度优先,例如第3层有dot和lot,先将dot和lot放到树上,再着手建立第4层。所以,需要一个辅助列表来保存每一层的的节点。以便于建立下一层。
2 为了保证树的建立过程中,不会出现倒回头的现象,所以已经添加到树上的节点需要标记,在我的代码中初始化节点的深度为-1,表示还未添加到树上。
3 树的两个分支可能包含同一个孩子节点,例如上面从第4层到第5层。cog节点有两个父节点,所以严格来说,这并不是一个树^_^ 另外,cog在处理dog节点的时候已经添加到树上,但是在处理log节点时,又处理了一次,看似于第2点矛盾,其实不然,因为dog和log是处在同一层的,为了记录所有可行的方案需要这样处理。
4 可以不记录节点的孩子节点情况,但是为了最后回溯结果,每个节点要记录自己的父节点(可能有多个父节点)。
5 回溯就比较简单了,用一个数组模拟栈,从节点B不停地往父节点方向走,记录所有可行路径。
具体还是看代码吧,我下面这个代码在庞果网提交并没有通过,应该还是有考虑不周的地方,恳请读者不吝赐教。
// MinOperationCount.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <string>#include <vector>#include <map>#include <set>#include <iostream>using namespace std;typedef struct _NODE{ vector<string> vecParentNode; int nDeep; bool isEnd;}NODE, *PNODE;bool IsNear(const string & strDest, const string & strSource){ int nLenDest = strDest.length(); int nLenSource = strSource.length(); if (nLenSource != nLenDest) { return false; } int nDiff = 0; for (int i = 0; i < nLenSource; i++) { if (strDest.at(i) != strSource.at(i)) { nDiff++; } } if (1 == nDiff) { return true; } return false;}bool FindNearString(set<string> &setStrFind, map<string, NODE> &mapStrNode, int nDeep){ bool bRet = false; set<string> setStrNext; set<string>::iterator itSet = setStrFind.begin(); for ( ; itSet != setStrFind.end(); itSet++) { map<string, NODE>::iterator it = mapStrNode.begin(); for ( ; it != mapStrNode.end(); it++) { if ( (-1 == it->second.nDeep || nDeep == it->second.nDeep) && IsNear(*itSet, it->first)) { it->second.nDeep = nDeep; it->second.vecParentNode.push_back(*itSet); setStrNext.insert(it->first); if (it->second.isEnd) { bRet = true; } } } } setStrFind = setStrNext; return bRet;}void OutputArray(string* arrayPath, int nDeep, vector<vector<string>> &vecResult){ vector<string> vecStr; for (int i = nDeep-1; i >= 0; i--) { vecStr.push_back(arrayPath[i]); } vecResult.push_back(vecStr);}void Recur(string* arrayPath, int i, int nDeep, string &strCur, map<string, NODE> &mapStrNode, vector<vector<string>> &vecResult){ arrayPath[i] = strCur; map<string, NODE>::iterator it = mapStrNode.find(strCur); if (it == mapStrNode.end()) { OutputArray(arrayPath, nDeep, vecResult); return; } for (int j = 0; j < (int)mapStrNode[strCur].vecParentNode.size(); j++) { i++; Recur(arrayPath, i, nDeep, mapStrNode[strCur].vecParentNode[j], mapStrNode, vecResult); i--; }}void GetMinPath(string &strBegin, string &strEnd, set<string> &setDict, vector<vector<string>> &vecResult){ if (strBegin == strEnd) { return; } map<string, NODE> mapStrNode; setDict.insert(strEnd); set<string>::iterator it = setDict.begin(); for ( ; it != setDict.end(); it++) { NODE node = {}; node.nDeep = -1;// -1 代表还没有插入到树上 node.isEnd = (*it == strEnd) ? true : false; mapStrNode[*it] = node; } //广度优先建立多叉树 set<string> setStrFind; setStrFind.insert(strBegin); int nDeep = 1; bool isFind = false; while (setStrFind.size() != 0 && !isFind) { isFind = FindNearString(setStrFind, mapStrNode, nDeep); nDeep++; } if (!isFind) { return; } string* arrayPath = new string[nDeep]; int i = 0; Recur(arrayPath, i, nDeep, strEnd, mapStrNode, vecResult); delete [] arrayPath;}class Solution{public: vector<vector<string>> findLadders(string start, string end, set<string>& dict) { vector<vector<string>> vecResult; GetMinPath(start, end, dict, vecResult); return vecResult; }};int _tmain(int argc, _TCHAR* argv[]){ string strBegin = "hit"; string strEnd= "cig"; set<string> setDict; setDict.insert("hot"); setDict.insert("git"); setDict.insert("dot"); setDict.insert("dog"); setDict.insert("lot"); setDict.insert("log"); setDict.insert("cog"); vector<vector<string>> vecResult; Solution so; vecResult = so.findLadders(strBegin, strEnd, setDict); vector<vector<string>>::iterator it = vecResult.begin(); for ( ; it != vecResult.end(); it++) { vector<string>::iterator itStr = it->begin(); for ( ; itStr != it->end(); itStr++) { cout<<*itStr<<" "; } cout<<"\n"; }return 0;}
update:
经过特例测试,发现是没有考虑到开始字符串出现在字典中的情况,所以将85行代码:
if (it == mapStrNode.end())
修改为:
if (it == mapStrNode.end() || nDeep == i+1) 即可。
- 【庞果英雄会】最小操作数
- 庞果英雄会——最小操作数
- 挑战庞果英雄会之最小操作数(失败求指教)
- 最小操作数-c#求解-英雄会在线编程题目
- 庞果英雄会 幸运数
- pongo(csdn英雄会)题解之最小操作数---leetcode之word ladder2
- 最小操作次数的简易版【解】--英雄会
- 英雄会-回文数
- 庞果最小操作数
- 庞果英雄会第二届在线编程大赛·线上初赛:AB数
- 最少操作次数(英雄会)
- 庞果英雄会 数组排序
- 庞果英雄会-整数问题
- 报数游戏(庞果英雄会)
- 二十进制数的加法--【英雄会】
- 英雄会编程挑战之回文数
- 【英雄会】二十进制数的加法
- 英雄会 高校俱乐部 最少操作次数
- 【毕业生】外包公司适合你么?
- ARM与 x86相比较
- 整理试卷
- Makefile之wildcard
- PAT_1003: Emergency
- 【庞果英雄会】最小操作数
- Post Office
- 二进制实用程序(objdump, readelf,ar, nm等)
- 黑马程序员———Java 开发环境搭建
- vincent歌曲翻译 很美很美很美
- 顺序主子式的英文翻译(定义)
- 浅析处理器技术与编程模型的发展趋势
- Plus One
- 2012 工作总结