25最小操作数问题
题目描述:
给定一个单词集合Dict,其中每个单词的长度都相同。现从此单词集合Dict中抽取两个单词A、B。希望通过若干次操作把单词A变成单词B,每次操作可以改变单词的一个字母,同时,每次操作后,新产生的单词必须是在给定的单词集合Dict中。求所有行得通步数最少的修改方法。
举个例子如下:
Given:
A ="hit"
B ="cog"
Dict =["hit","hot","dot","dog","lot","log","cog"]
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"。
分析:这个题目本质上是图的最短路径问题,此题看似跟字符串编辑距离相似,但其实区别特别大,原因是最短编辑距离是让某个单词增加一个字符或减少一个字符或修改一个字符达到目标单词,来求变换的最少次数,但此最小操作数问题就只是改变一个字符。
这个题目的关键就是如何根据词典Dict建立图,这么几个问题要思考,节点是什么?边如何建立?图是有方向的还是无方向的?
对于本题,我们的图的节点就是字典里的单词,两个节点有连边,对应着我们可以把一个单词按照规则变为另外一个单词。比如我们有单词hat,它应该与单词cat有一条连边,因为我们可以把h变为c,反过来我们也可以把c变为h,所以我们建立的连边应该是无向的。
如何建图?有两种办法:
1:我们可以把字典里的任意两个单词,通过循环判断一下这两个单词是否只有一个位置上的字母不同。即假设字典里有n个单词,我们遍历任意两个单词 的复杂度是O( ),如果每个单词长度为length,我们判断两个单词是否连边的复杂度是O(length),所以这个建图的总复杂度是 O( *length)。但当n比较大时,这个复杂度非常高。
2:把字典里地每个单词的每个位置的字母修改一下,从字典里查找一下,看修改后的单词是否在字典里出现过。若用基于red-black tree的map查找,其查找复杂度为O(logn),若用基于hashmap的unordered_map,则查找复杂度为O(1)。即我们需要遍历字典里地每一个单词O(n),尝试修改每个位置的每个字母,对每个位置我们需要尝试26个字母(其实是 25个,因为要改得和原来不同),因此这部分复杂度是O(26*length),总复杂度是O(26 * n * length)。
上面两种方法孰优孰劣呢?直接比较 *length 与 26 * n * length的大小。很明显,通常情况下,字典里的单词个数非常多,也就是n比较大,因此第二种方法效果会好一些。
建立好图之后,这个问题就转化为了最短路径的问题,不再赘述。下图是给定例子的图示:
http://blog.csdn.net/v_july_v/article/details/9921437