LeetCode – Word Ladder II (Java)

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that: 1) Only one letter can be changed at a time, 2) Each intermediate word must exist in the dictionary.

For example, given: start = "hit", end = "cog", and dict = ["hot","dot","dog","lot","log"], return:

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Analysis

This is an extension of Word Ladder.

The idea is the same. To track the actual ladder, we need to add a pointer that points to the previous node in the WordNode class.

In addition, the used word can not directly removed from the dictionary. The used word is only removed when steps change.

Java Solution

class WordNode{
    String word;
    int numSteps;
    WordNode pre;
 
    public WordNode(String word, int numSteps, WordNode pre){
        this.word = word;
        this.numSteps = numSteps;
        this.pre = pre;
    }
}
 
public class Solution {
    public List<List<String>> findLadders(String start, String end, Set<String> dict) {
        List<List<String>> result = new ArrayList<List<String>>();
 
        LinkedList<WordNode> queue = new LinkedList<WordNode>();
        queue.add(new WordNode(start, 1, null));
 
        dict.add(end);
 
        int minStep = 0;
 
        HashSet<String> visited = new HashSet<String>();  
        HashSet<String> unvisited = new HashSet<String>();  
        unvisited.addAll(dict);
 
        int preNumSteps = 0;
 
        while(!queue.isEmpty()){
            WordNode top = queue.remove();
            String word = top.word;
            int currNumSteps = top.numSteps;
 
            if(word.equals(end)){
                if(minStep == 0){
                    minStep = top.numSteps;
                }
 
                if(top.numSteps == minStep && minStep !=0){
                    //nothing
                    ArrayList<String> t = new ArrayList<String>();
                    t.add(top.word);
                    while(top.pre !=null){
                        t.add(0, top.pre.word);
                        top = top.pre;
                    }
                    result.add(t);
                    continue;
                }
 
            }
 
            if(preNumSteps < currNumSteps){
                unvisited.removeAll(visited);
            }
 
            preNumSteps = currNumSteps;
 
            char[] arr = word.toCharArray();
            for(int i=0; i<arr.length; i++){
                for(char c='a'; c<='z'; c++){
                    char temp = arr[i];
                    if(arr[i]!=c){
                        arr[i]=c;
                    }
 
                    String newWord = new String(arr);
                    if(unvisited.contains(newWord)){
                        queue.add(new WordNode(newWord, top.numSteps+1, top));
                        visited.add(newWord);
                    }
 
                    arr[i]=temp;
                }
            }
 
 
        }
 
        return result;
    }
}
Category >> Algorithms >> Interview  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>
  • Prabhat Meghwal

    “BSF” Really :O

  • Matias SM

    I don’t understand why would you need to keep the words in the dictionary (instead of deleting them right away, like in the previous case). If you reach a word again, it means that the result will be necessarily of a longer distance, so it can’t be in the shortest path. For the case of the end word, a simple validation when removing the word from the dict, will do the trick (or a different approach than having it in the dict).

    I believe you should keep processing to get all the shortest path solutions, but filtering should be done at the WordNode level. That is: once you find the shortest distance, you don’t process nodes with greater distance than that. Also, because of the way the “graph” is generated in this case, you know that nodes are queued in increasing distance order, so you can stop processing once the best distance is passed.

  • Prakash

    No, You are thinking it in with 1 example only .
    Code is correct on single Iteration of nested loop it will create all possible Threads for LinkedList.
    Each thread will return the different path once word match is found.
    Array List will hold all possible path.

  • Mohamed Hassan

    you must remove used elements to avoid loops

  • Billionaire

    Why remove used elements from hashset can boost performance? Isn’t that hashset is O(1) time complexity?

  • If anyone interested for both BFS and DFS approach for finding Word Ladder:

    http://javabypatel.blogspot.in/2015/10/word-ladder-doublets-word-links-word-golf.html

  • Haas Fiona

    I guess I am wrong. With BSF, the shortest path should be found first. Therefore, the first path should be the shorted path. The code is correct.

  • Haas Fiona

    The code might miss some cases when there are multiple path from start to end with multiple length.

  • Mimanshu

    This seems to be wrong. It will only print one path. After that queue will be empty and loop wont run.
    Am I inferring correctly?