最小操作数

题目详情

给了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",有以下两种可能:

  1. "hit" -> "hot" ->  "dot" ->  "dog" -> "cog";
  2. "hit" ->  "hot" ->  "lot" ->  "log"  ->"cog"。
答题说明
  1. A和B相同的情况下不需要做转换,此时直接返回空集;
  2. 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 ) );
	}

}

  

原文地址:https://www.cnblogs.com/i2u9/p/min_op_numbers.html