Word Ladder 解答

Question

Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the word list

For example,

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Note:

    • Return 0 if there is no such transformation sequence.
    • All words have the same length.
    • All words contain only lowercase alphabetic characters.

Solution 1 -- BFS

 

 1 class WordNode{
 2     String word;
 3     int numSteps;
 4     
 5     public WordNode(String word, int numSteps){
 6         this.word = word;
 7         this.numSteps = numSteps;
 8     }
 9 }
10 
11 public class Solution {
12     public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
13         Queue<WordNode> queue = new LinkedList<WordNode>();
14         queue.add(new WordNode(beginWord, 1));
15         
16         wordList.add(endWord);
17         
18         // 由于这里纪录了每个词的最小步数,所以不用两个list
19         while (queue.size() > 0) {
20             WordNode topNode = queue.remove();
21             String current = topNode.word;
22             
23             if (current.equals(endWord))
24                 return topNode.numSteps;
25             
26             char[] arr = current.toCharArray();
27             // 穷举法
28             for (int i = 0; i < arr.length; i++) {
29                 for (char c = 'a'; c <= 'z'; c++) {
30                     char tmp = arr[i];
31                     if (arr[i] != c)
32                         arr[i] = c;
33                     
34                     String newWord = new String(arr);
35                     if (wordList.contains(newWord)) {
36                         queue.add(new WordNode(newWord, topNode.numSteps + 1));
37                         wordList.remove(newWord);
38                     }
39                     arr[i] = tmp;
40                 }
41             }
42         }
43         return 0;
44     }
45 }

 

Solution 2 -- BFS & Adjacency List

Basic idea is: 1. construct adjacency list 2. BFS

Constructing adjacency list uses O(n2) time, and BFS is O(n). Total time complexity is O(n2), when testing in leetcode, it reports "time limit exceeded".

 1 public class Solution {
 2     public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
 3         if (wordList == null)
 4             return -1;
 5         int step = 1;
 6         if (beginWord.equals(endWord))
 7             return 1;
 8         // Construct adjacency lists for words
 9         // Do not forget start word and end word
10         wordList.add(beginWord);
11         wordList.add(endWord);
12         Map<String, List<String>> adjacencyList = new HashMap<String, List<String>>();
13         Map<String, Boolean> visited = new HashMap<String, Boolean>();
14         int length = wordList.size();
15         String[] wordList2 = new String[length];
16         int i = 0;
17         for (String current : wordList) {
18             wordList2[i] = current;
19             i++;
20         }
21         // Initialization
22         for (i = 0; i < length; i++) {
23             adjacencyList.put(wordList2[i], new ArrayList<String>());
24             visited.put(wordList2[i], false);
25         }
26         
27         for (i = 0; i < length; i++) {
28             String current = wordList2[i];
29             // Construct adjacency list for each element
30             for (int j = i + 1; j < length; j++) {
31                 String next = wordList2[j];
32                 if (isAdjacent(current, next)) {
33                     List<String> list1 = adjacencyList.get(current);
34                     list1.add(next);
35                     adjacencyList.put(current, list1);
36                     List<String> list2 = adjacencyList.get(next);
37                     list2.add(current);
38                     adjacencyList.put(next, list2);
39                 }
40             }
41         }
42         
43         // BFS
44         List<String> current = new ArrayList<String>();
45         List<String> next;
46         current.add(beginWord);
47         visited.put(beginWord, true);
48         while (current.size() > 0) {
49             step++;
50             next = new ArrayList<String>();
51             for (String currentString : current) {
52                 List<String> neighbors = adjacencyList.get(currentString);
53                 if (neighbors == null)
54                     continue;
55                 for (String neighbor : neighbors) {
56                     if (neighbor.equals(endWord))
57                         return step;
58                     if (!visited.get(neighbor)) {
59                         next.add(neighbor);
60                         visited.put(neighbor, true);
61                     }
62                 }
63             }
64             current = next;
65         }
66         return -1;
67         
68     }
69     
70     private boolean isAdjacent(String current, String next) {
71         if (current.length() != next.length())
72             return false;
73         int length = current.length();
74         int diff = 0;
75         for (int i = 0; i < length; i++) {
76             char a = current.charAt(i);
77             char b = next.charAt(i);
78             if (a != b)
79                 diff++;
80         }
81         if (diff == 1)
82             return true;
83         return  false;
84     }
85 }

 Python version

 1 from collections import deque
 2 from collections import defaultdict
 3     
 4 class Solution:
 5     def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
 6         if endWord not in wordList:
 7             return 0
 8         queue = deque()
 9         queue.append((beginWord, 1))
10         visited = set([beginWord])
11         adjacency_map = defaultdict(list)
12         L = len(beginWord)
13         # Pre-process
14         for word in wordList:
15             for i in range(L):
16                 adjacency_map[word[:i] + "*" + word[i+1:]].append(word)
17         # BFS
18         while queue:
19             curr_word, curr_steps = queue.popleft()
20             if curr_word == endWord:
21                 return curr_steps
22             # List all possibilities
23             for i in range(L):
24                 key = curr_word[:i] + "*" + curr_word[i+1:]
25                 if key in adjacency_map:
26                     neighbors = adjacency_map[key]
27                     for neighbor in neighbors:
28                         if neighbor == endWord:
29                             return curr_steps + 1
30                         if neighbor not in visited:
31                             queue.append((neighbor, curr_steps + 1))
32                             visited.add(neighbor)
33                     adjacency_map[key] = {}
34         return 0

 

posted @ 2015-10-10 11:08  树獭君  阅读(233)  评论(0编辑  收藏  举报