[LeetCode]Word Ladder, Word Ladder II

Word Ladder

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:c++

  1. Only one letter can be changed at a timespa

  2. Each intermediate word must exist in the word listcode

For example,orm

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.rem

Note:字符串

  • Return 0 if there is no such transformation sequence.get

  • All words have the same length.it

  • All words contain only lowercase alphabetic characters.io

分析

典型的BFS題。一層一層的找,分別對應修改一個字符,兩個字符,三個字符...直至發現結尾字符串, 注意用一個Set寸已經訪問過的字符串,避免重複。form

複雜度

time: O(n), space: O(n)

代碼

public class Solution {
    public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
    
        Queue<String> q = new LinkedList<String>();
        q.add(beginWord);
        Set<String> visited = new HashSet<String>();
        visited.add(beginWord);
        int level = 0;
        
        while (!q.isEmpty()) {
            int len = q.size();
            level++;
            for (int i = 0; i < len; i++) {
                String word = q.remove();
                for (int j = 0; j < word.length(); j++) {
                    char[] chars = word.toCharArray();
                    for (char c = 'a'; c <= 'z'; c++) {
                        chars[j] = c;
                        String nextWord = new String(chars);
                        if (nextWord.equals(endWord)) {
                            return level + 1;
                        }
                        if (!visited.contains(nextWord) && wordList.contains(nextWord)) {
                            q.add(nextWord);
                            visited.add(nextWord);
                        }
                    }
                }
            }
        }
        
        return 0;
    }
}

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:

  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"]
Return

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

Note:

  • All words have the same length.

  • All words contain only lowercase alphabetic characters.

分析

若是要返回全部的結果,問題變複雜了些。由於用BFS相對於DFS的劣勢就是不方便存儲結果。這種須要返回全部結果的,仍是應該從DFS考慮,可是直接應用DFS複雜度會很高,由於這道題咱們只要知道結尾就行了,不用繼續往下搜。

因此問題就轉化成怎樣用DFS的同時又能夠限制DFS的深度,因此咱們能夠BFS與DFS結合。先用BFS搜到結尾字符串,而後把中途全部的字符串及其跟起始字符的edit distance存在一個map裏。這樣的話,咱們就能夠從結尾字符串開始DFS,只有Map內的字符串才考慮繼續DFS,直至搜到起始字符。

注意這裏有個小技巧,就是爲何不從起始字符串開始DFS直至搜到結尾字符串,而是反過來。這裏能夠腦子裏想像一個圖,若是從起始字符串開始搜,到最後一層的話會有不少無效搜索,由於那層咱們只須要找到結尾字符串,那麼多無效的搜索到最一層太浪費時間。反之,若是咱們從結尾字符串開始DFS, 咱們把起始層控制在一個字符串,整個圖先愈來愈寬,而後愈來愈窄直到起始字符串,而非一直愈來愈寬直到結尾字符串那層。

複雜度

time: O(n), space: O(n)

代碼

public class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, Set<String> wordList) {
        Map<String, Integer> distMap = new HashMap<String, Integer>(); 
        getDistance(beginWord, endWord, wordList, distMap);
        List<List<String>> res = new ArrayList<List<String>>();
        dfs(res, new ArrayList<String>(), distMap, wordList, endWord, beginWord);
        return res;
    }
    
    public void dfs(List<List<String>> res, List<String> cur, Map<String, Integer> distMap, Set<String> wordList, String word, String des) {
        if (word.equals(des)) {
            List<String> list = new ArrayList<String>(cur);
            list.add(des);
            Collections.reverse(list);
            res.add(list);
            return;
        }
        
        cur.add(word);
        for (int i = 0; i < word.length(); i++) {
            char[] chars = word.toCharArray();
            for (char c = 'a'; c <= 'z'; c++) {
                chars[i] = c;
                String nextWord = new String(chars);

                // 不只字典中含有,兩字符串也是要在路徑的相鄰位置即距離差1
                if (distMap.containsKey(nextWord) && distMap.get(nextWord) == distMap.get(word) - 1) {
                    dfs(res, cur, distMap, wordList, nextWord, des);
                }
            }
        }
        cur.remove(cur.size() - 1);
    }
    
    // 用Word Ladder I的方法把候選字符串及其距離存入map,縮小DFS範圍。
    public void getDistance(String beginWord, String endWord, Set<String> wordList, Map<String, Integer> distMap) {
        distMap.put(beginWord, 1);
        Queue<String> q = new LinkedList<String>();
        q.add(beginWord);
        
        while (!q.isEmpty()) {
            String word = q.remove();
            for (int j = 0; j < word.length(); j++) {
                char[] chars = word.toCharArray();
                for (char c = 'a';  c <= 'z'; c++) {
                    chars[j] = c;
                    String nextWord = new String(chars);
                    if (nextWord.equals(endWord)) {
                        distMap.put(nextWord, distMap.get(word) + 1);
                        return;
                    }
                    if (wordList.contains(nextWord) && !distMap.containsKey(nextWord)) {
                        distMap.put(nextWord, distMap.get(word) + 1);
                        q.add(nextWord);
                    }
                }
            }
        }
    }
}
相關文章
相關標籤/搜索