# 126. Word Ladder II

A **transformation sequence** from word `beginWord` to word `endWord` using a dictionary `wordList` is a sequence of words `beginWord -> s1 -> s2 -> ... -> sk` such that:

* Every adjacent pair of words differs by a single letter.
* Every `si` for `1 <= i <= k` is in `wordList`. Note that `beginWord` does not need to be in `wordList`.
* `sk == endWord`

Given two words, `beginWord` and `endWord`, and a dictionary `wordList`, return *all the **shortest transformation sequences** from* `beginWord` *to* `endWord`*, or an empty list if no such sequence exists. Each sequence should be returned as a list of the words* `[beginWord, s1, s2, ..., sk]`.

&#x20;

**Example 1:**

```
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: [["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
Explanation: There are 2 shortest transformation sequences:
"hit" -> "hot" -> "dot" -> "dog" -> "cog"
"hit" -> "hot" -> "lot" -> "log" -> "cog"
```

**Example 2:**

```
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence.
```

&#x20;

**Constraints:**

* `1 <= beginWord.length <= 5`
* `endWord.length == beginWord.length`
* `1 <= wordList.length <= 1000`
* `wordList[i].length == beginWord.length`
* `beginWord`, `endWord`, and `wordList[i]` consist of lowercase English letters.
* `beginWord != endWord`
* All the words in `wordList` are **unique**.

### **Solution:**

[**https://www.jiuzhang.com/problem/word-ladder-ii/**](https://www.jiuzhang.com/problem/word-ladder-ii/)\
**Version 1:**&#x20;

从 end 到 start 做一次 BFS，并且把距离 end 的距离都保存在 distance 中。 然后在从 start 到 end 做一次 DFS，每走一步必须确保离 end 的 distance 越来越近。

这种解法是：end -> start : bfs   。start -> end : dfs

与另外一个代码中提前建立 index 不同，这里是在寻找下一个变换单词的时候，再去获得对应的单词列表。一个单词最多有 L 个字符，每个字符有 25 种不同的变化（26个字母除掉这个位置上的字母），然后 check 一下在不在 dict 里就知道是不是 next word 了。

```
/class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
    
        List<List<String>> result = new ArrayList<>();
        Set<String> dict = new HashSet<String>();
        // need to add this stage, otherwise it always return null
        dict.add(beginWord);
        for(String word : wordList)
        {
            dict.add(word);
        }
        if(!dict.contains(endWord)) return result;
        
        Map<String, Integer> distance = new HashMap<String, Integer>();
        bfs(distance, endWord, beginWord, dict);
        
        List<String> path = new ArrayList<String>();
        // first add the beginWord
        path.add(beginWord);
        dfs(result, path, distance, beginWord, endWord, dict);
        return result;
    }
    
    
    public void bfs(Map<String, Integer> distance , String beginWord, String endWord, Set<String> wordList)
    {
        Queue<String> queue = new LinkedList<String>();
        queue.offer(beginWord);
        distance.put(beginWord, 0);
        while(!queue.isEmpty())
        {
            for(int i = 0; i< queue.size(); i++)
            {
                String current = queue.poll();
                if(current.equals(endWord))
                {
                    return;
                }
                List<String> neighbors  = getNeighbours(current, wordList);
                for(String next: neighbors)
                {
                    if(!distance.containsKey(next))
                    {
                        queue.offer(next);
                        distance.put(next, distance.get(current) + 1);
                    }
                }
            }
        }
    }
    
    public void dfs(List<List<String>> result, 
                    List<String> path,
                    Map<String, Integer> distance, 
                    String currentWord, 
                    String endWord, 
                    Set<String> wordList)
    {
        //path.add(currentWord);
        if(currentWord.equals(endWord))
        {
            result.add(new ArrayList<String>(path));
            // can't add return;
        }
        else
        {
            for(String neighbor: getNeighbours(currentWord, wordList))
            {
                if(distance.containsKey(neighbor) && distance.containsKey(currentWord) && distance.get(currentWord) == distance.get(neighbor) + 1)
                {
                    path.add(neighbor);
                    dfs(result, path, distance, neighbor, endWord, wordList);
                    path.remove(path.size()-1);
                }
            }
        } 
        //path.remove(path.size()-1);
    }

    
    public List<String> getNeighbours(String current, Set<String> dict)
    {
        List<String> result = new ArrayList<String>();
        for(int i = 0; i< current.length(); i++)
        {
            char c = current.charAt(i);
            for(char j = 'a' ; j <= 'z'; j++)
            {
                if(c == j) continue;
                char[] wordArray = current.toCharArray();
                wordArray[i] = j;
                String neighbor = new String(wordArray);
                if(dict.contains(neighbor))
                {
                    result.add(neighbor);
                }
            }
        }
        return result;
    }
}
```

**Version 2:**&#x20;

BFS from start to end寻找最短路径，DFS from end to start 找到所有路径。

思路上和[Word Ladder](http://blog.csdn.net/linhuanmars/article/details/23029973)是比较类似的，但是因为是要求出所有路径，仅仅保存路径长度是不够的，而且这里还有更多的问题，那就是为了得到所有路径，不是每个结点访问一次就可以标记为visited了，因为有些访问过的结点也会是别的路径上的结点，所以访问的集合要进行回溯（也就是标记回未访问）。所以时间上不再是一次广度优先搜索的复杂度了，取决于结果路径的数量。同样空间上也是相当高的复杂度，因为我们要保存过程中满足的中间路径到某个[数据结构](http://lib.csdn.net/base/datastructure)中，以便最后可以获取路径，这里我们维护一个HashMap，把一个结点前驱结点都进行保存。在LeetCode中用[Java](http://lib.csdn.net/base/javase)实现上述[算法](http://lib.csdn.net/base/datastructure)非常容易超时。为了提高算法效率，需要注意一下两点：

1）在替换String的某一位的字符时，先转换成char数组再操作；

2）如果按照正常的方法从start找end，然后根据这个来构造路径，代价会比较高，因为保存前驱结点容易，而保存后驱结点则比较困难。

所以我们在广度优先搜索时反过来先从end找start，最后再根据生成的前驱结点映射从start往end构造路径，这样算法效率会有明显提高。

```
 public List<List<String>> findLadders(String start, String end, Set<String> dict) {

       //store the node and its neighbor
       HashMap<String,List<String>> graph=new HashMap<String,List<String>>();
       //store the distance with end
       HashMap<String,Integer> distance=new HashMap<String,Integer>();
       dict.add(start);
       dict.add(end);

       bfs(start,end,dict,graph,distance);

       List<List<String>> result=new ArrayList<>();
       List<String> path=new ArrayList<String>();

       dfs(result,path,start,end,graph,distance);

       return result;
   }

   public List<String> neighbor(String str,Set<String> dict){
       List<String> neighbor=new ArrayList<String>();
       for(int i=0;i<str.length();i++){
           char ch=str.charAt(i);
           for(char j='a';j<='z';j++){
               if(ch==j) continue;
               //这三句话生成新的string
               char[] string=str.toCharArray();
               string[i]=j;
               String newstr=new String(string);

               if(dict.contains(newstr)){
                   neighbor.add(newstr);
               }
           }
       }
       return neighbor;
   }

   //from start to end
   public void bfs(String start,
                   String end,
                   Set<String> dict,
                   HashMap<String,List<String>> graph,
                   HashMap<String,Integer> distance){
       Queue<String> queue=new LinkedList<String>();
       queue.add(start);
       distance.put(start,0);
       //initial graph
       for(String str: dict){
           graph.put(str, new ArrayList<String>());
       }

       while(!queue.isEmpty()){
           String current=queue.poll();
           for(String element :neighbor(current,dict)){
               graph.get(current).add(element);
               if(!distance.containsKey(element)){
                   distance.put(element,distance.get(current)+1);
                   queue.offer(element);
               }
           }
       }

   }

   //from end to start
   public void dfs(List<List<String>> result,
                   List<String> path,
                   String start,
                   String current,
                   HashMap<String,List<String>> graph,
                   HashMap<String,Integer> distance){
       path.add(current);
       if(current.equals(start)){
           Collections.reverse(path);
           result.add(new ArrayList<String>(path));
           Collections.reverse(path);
       }else{
           for(String next :graph.get(current)){
               if(distance.containsKey(next) && distance.get(current)==distance.get(next)+1){
                   dfs(result,path,start,next,graph,distance);
               }
           }
       }
       path.remove(path.size()-1);
   }
```
