127. 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:

  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.

鏈接: http://leetcode.com/problems/word-ladder/

題解:

一上來無思路,想象跟Dijkstra單源最短路徑很像,但不知道怎么寫。於是大肆搜刮資料,主要參考了code ganker和小瑩子的代碼和post。寫的話和Binary Tree Level Order Traversal很接近,就是標准的用queue和一個visited數組或者hashset來標記訪問過的元素,用curLevel和nextLevel來記錄哪一層BFS。 圖的算法需要多練習,相信練好了就會像打開眾秒之門一樣。

Time Complexity - O(min(26^L, size(wordList)), Space Complexity - O(min(26^L, size(wordList)),  L為 word length

public class Solution {
    public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
        if(beginWord == null || endWord == null || wordList == null || wordList.size() == 0 || beginWord.equals(endWord))
            return 0;
        Queue<String> q = new LinkedList<>();
        q.offer(beginWord);
        int curLevel = 1, nextLevel = 0, steps = 1;
        HashSet<String> visited = new HashSet<>();
        
        while(!q.isEmpty()) {
            String word = q.poll();
            curLevel--;
            
            for(int i = 0; i < word.length(); i++) {
                char[] wordArray = word.toCharArray();
                
                for(char j = 'a'; j <= 'z'; j++) {
                    wordArray[i] = j;
                    String newWord = String.valueOf(wordArray);
                    if(newWord.equals(endWord))
                        return steps + 1;
                    if(wordList.contains(newWord) && !visited.contains(newWord)) {
                        q.offer(newWord);
                        visited.add(newWord);
                        nextLevel++;
                    }
                }
            }
            
            if(curLevel == 0) {
                curLevel = nextLevel;
                nextLevel = 0;
                steps++;
            } 
        }
        
        return 0;
    }
}

 

二刷:

Java:

One-way BFS:

復雜度並不好計算,我們每一次找到新單詞以后,要計算26個字母組合的可能性,對於每一個新組成的單詞,我們要判斷是存在於set里。branching factor = 26,depth = 單詞長度L,set中的查找我們粗略算為O(1),所以這一部分的復雜度就是26 ^ L。假如我們有x個單詞滿足條件,那么接下來我們要對這x個單詞進行同樣的步驟。最壞情況下我們要檢查set中所有的n個單詞,所以時間復雜度應該是O(n * 26L ) , 空間復雜度也一樣。

Time Complexity - O(n * 26L),  Space Complexity - O(n * 26L)

public class Solution {
    public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
        if (beginWord == null || endWord == null || wordList == null) return 0;
        Queue<String> q = new LinkedList<>();
        q.offer(beginWord);
        int steps = 1, curLevel = 1, nextLevel = 0;
        Set<String> visited = new HashSet<>(5000);
        visited.add(beginWord);
        
        while (!q.isEmpty()) {
            String word = q.poll();
            char[] wordArr = word.toCharArray();
            curLevel--;
            for (int i = 0; i < wordArr.length; i++) {
                char tmp = wordArr[i];
                for (char c = 'a'; c <= 'z'; c++) {
                    if (c != tmp) wordArr[i] = c;
                    String newWord = String.valueOf(wordArr);
                    if (newWord.equals(endWord)) return steps + 1;
                    if (!visited.contains(newWord) && wordList.contains(newWord)) {
                        q.offer(newWord);
                        nextLevel++;
                        visited.add(newWord);
                    }
                }
                wordArr[i] = tmp;
            }
            if (curLevel == 0) {
                curLevel = nextLevel;
                nextLevel = 0;
                steps++;
            }
        }
        return 0;
    }
}

 

三刷:

三刷使用了 Two-way BFS。存兩個HashSet beginSet和endSet,然后每次從較小的hashset開始進行下一步的計算,把BFS的結果存在一個tmp HashSet中。最后更新beginSet = tmp。 其他過程跟1-way BFS基本一樣,不同的一點是,假如newWord存在於endSet中,我們立刻可以返回steps + 1。 這里新建立一個wordList的copy,再從其中移除已訪問過的單詞,也可以增加一些速度。

代碼主要參考了@Moriarty。

Java:

Time Complexity - O(n * 26L),  Space Complexity - O(n * 26L)

public class Solution {
    public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
        if (beginWord == null || endWord == null || wordList == null || beginWord.equals(endWord)) return 0;
        Set<String> beginSet = new HashSet<>(wordList.size());
        Set<String> endSet = new HashSet<>(wordList.size());
        Set<String> list = new HashSet(wordList);       //have a copy of input
        
        beginSet.add(beginWord);
        endSet.add(endWord);
    
        int steps = 1, curLevel = 1, nextLevel = 0;
        
        while (!beginSet.isEmpty() && !endSet.isEmpty()) {
            if (beginSet.size() > endSet.size()) {
                Set<String> set = beginSet;
                beginSet = endSet;
                endSet = set;
            }
            
            Set<String> tmpSet = new HashSet<String>();
            
            for (String word : beginSet) {
                char[] wordArr = word.toCharArray();
                for (int i = 0; i < wordArr.length; i++) {
                    char ch = wordArr[i];
                    for (char c = 'a'; c <= 'z'; c++) {
                        wordArr[i] = c;
                        String newWord = String.valueOf(wordArr);
                        if (endSet.contains(newWord)) return steps + 1;
                        if (list.contains(newWord)) {
                            list.remove(newWord);
                            tmpSet.add(newWord);
                        }
                    }
                    wordArr[i] = ch;
                }
            }
            beginSet = tmpSet;
            steps++;
        }
        return 0;
    }
}

 

四刷:

class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        if (beginWord == null || endWord == null || wordList == null) return 0;
        Queue<String> q = new LinkedList<>();
        q.offer(beginWord);
        int steps = 1, curLevel = 1, nextLevel = 0;
        Set<String> visited = new HashSet<>(5000);
        visited.add(beginWord);
        
        Set<String> set = new HashSet<>();
        for (String word : wordList) set.add(word);
        
        while (!q.isEmpty()) {
            String word = q.poll();
            char[] wordArr = word.toCharArray();
            curLevel--;
            for (int i = 0; i < wordArr.length; i++) {
                char tmp = wordArr[i];
                for (char c = 'a'; c <= 'z'; c++) {
                    if (c != tmp) wordArr[i] = c;
                    String newWord = String.valueOf(wordArr);
                    
                    if (!visited.contains(newWord) && set.contains(newWord)) {
                        if (newWord.equals(endWord)) return steps + 1;
                        q.offer(newWord);
                        nextLevel++;
                        visited.add(newWord);
                    }
                }
                wordArr[i] = tmp;
            }
            if (curLevel == 0) {
                curLevel = nextLevel;
                nextLevel = 0;
                steps++;
            }
        }
        
        return 0;
    }
}

 

 

Reference:

http://blog.csdn.net/linhuanmars/article/details/23029973

http://www.cnblogs.com/springfor/p/3893499.html

http://www.programcreek.com/2012/12/leetcode-word-ladder/

http://www.geeksforgeeks.org/breadth-first-traversal-for-a-graph/

https://leetcode.com/discuss/48083/share-python-solutions-concise-160ms-optimized-solution-100ms

https://leetcode.com/discuss/50930/java-solution-using-dijkstras-algorithm-with-explanation

https://leetcode.com/discuss/42006/easy-76ms-c-solution-using-bfs

https://leetcode.com/discuss/44079/super-fast-java-solution-using-two-end-bfs

https://leetcode.com/discuss/43940/another-accepted-java-solution-bfs

https://leetcode.com/discuss/28573/share-my-two-end-bfs-in-c-80ms

https://leetcode.com/discuss/68935/two-end-bfs-in-java-31ms

https://leetcode.com/discuss/30872/short-java-bfs-solution

https://leetcode.com/discuss/20587/accepted-java-solution-based-on-dijkstras-algorithm

https://leetcode.com/discuss/23274/a-c-bfs-solution-without-constructing-words

http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-spring-2008/recitations/recitation12.pdf


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM