题目详情
给了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"。
答题说明
- A和B相同的情况下不需要做转换,此时直接返回空集;
- main函数是为方便你在提交代码之前进行在线编译测试,可不完成。
思路:分析问题的本质, 单词连线即可得到一个无向 无权图,问题即是求图中两个节点的所有最短路径。因为最短路径 很容易想到 广度优先,或者 Dijstra算法。
① 分层搜索
② 逐层计算路径
源码如下:
package hero;
import java.util.*;
public class Minopnum {
public Vector<Vector<String>> findLadders(String start, String end, Set<String> dict) {
Vector<Vector<String>> retval = new Vector<Vector<String>>();
// check arguments
if( start.equals(end) ){
return retval;
} else if( start == null || end == null ){
return null ;
}
int ab = similar(start, end) , L = start.length() ;
if( ab == 1){
Vector<String> path = new Vector<String>();
path.add(start);
path.add(end);
retval.add(path) ;
return retval;
} else if( ab == 3){
return retval;
}
if( dict == null || dict.isEmpty() ){
return retval ;
}
// main process
Vector<HashSet<String>> tiers = new Vector<HashSet<String>>() ;
HashSet<String> ftier = new HashSet<String>();
ftier.add(start);
tiers.add(ftier);
HashMap<String,HashSet<String>> prenodes = new HashMap<String,HashSet<String>>();
HashSet<String> unused = new HashSet<String>();
for(String word : dict){
if(word != null && word.length() == L ){
unused.add(word);
}
}
if( unused.contains(start)){
unused.remove(start);
}
if( unused.contains(end)){
unused.remove(end);
}
boolean exists = false ;
HashSet<String> ends = findlikes(end, unused);
while( ! unused.isEmpty() ){
HashSet<String> nexttier = new HashSet<String>();
HashSet<String> deadwords = new HashSet<String>();
boolean endtier = false;
HashSet<String> last = tiers.get( tiers.size() - 1 );
for(String word: last ){
HashSet<String> wto = findlikes(word, unused);
if( wto.isEmpty() ){
deadwords.add(word);
} else {
nexttier.addAll(wto);
for(String tword: wto){
if( ! prenodes.containsKey(tword) ){
prenodes.put(tword, new HashSet<String>());
}
prenodes.get(tword).add(word);
}
if( endtier == false ){
HashSet<String> t = setsame(ends,wto);
if( ! t.isEmpty() ){
endtier = true;
exists = true;
}
}
}
}
if( nexttier.isEmpty() ){
break;
}
for(String w: deadwords){
last.remove(w);
}
for(String w: nexttier){
unused.remove(w);
}
if( endtier ){
tiers.add( setsame(ends,nexttier ) );
break;
} else {
tiers.add(nexttier);
}
} // end each tier
if( ! exists ){ // after find all nodes
return retval;
}
prenodes.put(end, tiers.get( tiers.size() - 1));
HashSet<String> etier = new HashSet<String>();
etier.add(end);
tiers.add(etier);
HashMap<String,Vector<Vector<String>>> pathes = new HashMap<String,Vector<Vector<String>>>();
Vector<String> startpath = new Vector<String>();
startpath.add(start);
retval.add(startpath);
pathes.put(start, retval);
for(int i=1,Lt=tiers.size();i<Lt;i++){
for(String w : tiers.get(i) ){
pathes.put(w, new Vector<Vector<String>>() );
for(String p : prenodes.get(w) ){
for(Vector<String> path : pathes.get(p) ){
@SuppressWarnings("unchecked")
Vector<String> newpath = (Vector<String>) path.clone();
newpath.add(w);
pathes.get(w).add(newpath);
}
}
}
}
return pathes.get(end) ;
}
public static HashSet<String> findlikes(String a, Set<String> words){
HashSet<String> likes = new HashSet<String>() ;
for(String s : words ){
if( similar(a, s) == 1 ){
likes.add(s);
}
}
return likes ;
}
public static int similar(String a, String b){
assert a != null && b != null;
if( a.equals(b) ){
return 0 ;
} else if( a.length() != b.length() ){
return 3;
}
boolean diff = false;
for(int i=0,L=a.length();i<L;i++){
if( a.charAt(i) != b.charAt(i) ){
if( diff ){
return 2;
}
diff = true;
}
}
return 1 ;
}
public static HashSet<String> setsame(HashSet<String> a, HashSet<String> b){
HashSet<String> c = new HashSet<String>();
for(String w : a){
if( b.contains(w)){
c.add(w);
}
}
return c;
}
public static void main(String[] args) {
/*
* hot dog [cog, dog, dot, hog, hop, hot, pot, tot]
*/
String[] d = {"cog", "dog", "dot", "hog", "hop", "hot", "pot", "tot"} ;
Set<String> dict = new HashSet<String>();
for(int i=0;i<d.length;i++){
dict.add(d[i]);
}
Minopnum t = new Minopnum();
System.out.println( t.findLadders("hot", "dog", dict ) );
}
}