Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions p126.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
126. Word Ladder II

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

Only one letter can be changed at a time
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,

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

Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
*/

public class Solution {

public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole function is too long. Try to break it down to a few pieces

Map<String, Integer> map = new HashMap<>();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name map here is confusing. Actually this is a map that records the shortest distance from begin word.

Map<String, Set<String>> neighbors = new HashMap<>();
neighbors.put(beginWord, new HashSet<>());
map.put(beginWord, -1);
Set<String> wordSet = new HashSet<>();
for(String word : wordList){
wordSet.add(word);
map.put(word, -1);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: map.put(word, cur_distance - 1);

neighbors.put(word, new HashSet<>());
}
int distance = 0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to rename it to cur_distance

boolean found = false;
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
while(!queue.isEmpty()){
int len = queue.size();
for(int i = 0; i < len; i++){
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need this for loop. This for loop does nothing good but complex your logic.
While() {
// Only process one node each time
// Pop element from queue
// Update distance and find neighbors.
// Push neighbors into queue.
}

String curWord = queue.poll();
if(map.get(curWord) == -1 || map.get(curWord) > distance){
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition can be simplified. Think about if such scenario exists: you visit a node, and the node has been visited and it has a larger distance than current distance. Is that possible?

map.put(curWord, distance);
}
if(curWord.equals(endWord)){
found = true;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The found flag is only used to break the loop. Why don't you break here?

}
for(int j = 0; j < curWord.length(); j++){
char[] arr = curWord.toCharArray();
for(char c = 'a'; c <= 'z'; c++){
if(c != arr[j]){
arr[j] = c;
}
String newWord = new String(arr);
if(wordSet.contains(newWord)){
if(map.get(newWord) == -1){
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a duplicated check.

queue.offer(newWord);
neighbors.get(curWord).add(newWord);
}
}
}
}
}
if(found) break;
distance++;
}
List<List<String>> wraplist = new ArrayList<>();
dfs(map, neighbors, new ArrayList<>(), wraplist, beginWord, endWord);
return wraplist;
}

public void dfs(Map<String, Integer> map, Map<String, Set<String>> neighbors, List<String> sublist, List<List<String>> wraplist, String curWord, String endWord){
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename dfs to something meaningful.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So a very good question here, if you can answer this, then you probably know why your program running slow.

What is the difference between

  • DFS from begin to end
  • DFS from end to begin


if(curWord.equals(endWord)){
sublist.add(curWord);
wraplist.add(new ArrayList<>(sublist));
sublist.remove(sublist.size() - 1);
return;
}

for(String neighbor : neighbors.get(curWord)){
sublist.add(curWord);
if(map.get(neighbor) == map.get(curWord) + 1){
dfs(map, neighbors, sublist, wraplist, neighbor, endWord);
}
sublist.remove(sublist.size() - 1);
}
}
}