题目
原文:
Given two words of equal length that are in a dictionary, write a method to transform one word into another word by changing only one letter at a time. The new word you get in each step must be in the dictionary.
EXAMPLE:
Input: DAMP, LIKE
Output: DAMP -> LAMP -> LIMP -> LIME -> LIKE
译文:
给两个长度相等并在字典存在的单词,写一个方法将一个单词转变为另一个单词,每次只能改变一个字母,并且每次新的单词都可以在字典中找到。
例如:
输入:DAMP, LIKE
输出:DAMP->LAMP->LIMP->LIME->LIKE
解答
ctci解法:
虽然这个问题似乎很难,它实际上是一个简单的修改breadth-first-search。每个单词在我们的“图”分支的所有单词在字典里是一个编辑。有趣的部分是如何实现它,我们应该构建一个图去吗?我们可以,但有一个更简单的方法。我们可以用一个“回溯地图。“在这回溯地图,如果B[v]= w,然后你知道你编辑v获取w。当我们到达结束的单词,我们可以使用此回溯地图反复扭转我们的路径。看下面的代码:
LinkedList<String> transform(String startWord, String stopWord,Set<String> dictionary) {
startWord = startWord.toUpperCase();
stopWord = stopWord.toUpperCase();
Queue<String> actionQueue = new LinkedList<String>();
Set<String> visitedSet = new HashSet<String>();
Map<String, String> backtrackMap = new TreeMap<String, String>();
actionQueue.add(startWord);
visitedSet.add(startWord);
while (!actionQueue.isEmpty()) {
String w = actionQueue.poll();
// For each possible word v from w with one edit operation
for (String v : getOneEditWords(w)) {
if (v.equals(stopWord)) {
// Found our word! Now, back track.
LinkedList<String> list = new LinkedList<String>();
// Append v to list
list.add(v);
while (w != null) {
list.add(0, w);
w = backtrackMap.get(w);
}
return list;
}
// If v is a dictionary word
if (dictionary.contains(v)) {
if (!visitedSet.contains(v)) {
actionQueue.add(v);
visitedSet.add(v); // mark visited
backtrackMap.put(v, w);
}
}
}
}
return null;
}
Set<String> getOneEditWords(String word) {
Set<String> words = new TreeSet<String>();
for (int i = 0; i < word.length(); i++) {
char[] wordArray = word.toCharArray();
// change that letter to something else
for (char c = ‘A’; c <= ‘Z’; c++) {
if (c != word.charAt(i)) {
wordArray[i] = c;
words.add(new String(wordArray));
}
}
}
return words;
}
n是开始单词的长度,m是同样长度的单词在字典里的数量。该算法的运行时间复杂度是O(n*m)因为while循环将出列最多m个独特的单词。for循环是O(n),因为它遍历字符串应用固定每个字符的替代品的数量。
---EOF---