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

posted @ 2015-04-19 00:39  YRB  阅读(2022)  评论(2编辑  收藏  举报