zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    变量系列教材 (一)- Java中 什么是变量
    HelloWorld系列(七)- 各种软件、工具版本兼容说明
    HelloWorld系列(六)- eclipse常见的使用技巧
    HelloWorld系列(四)- 使用ecipse创建第一个 java project
    HelloWorld系列(二)- 用命令行中编写第一个 java 程序
    HelloWorld系列(一)- 手把手教你做JDK环境变量配置
    面向对象(三)- Java类的方法
    [LeetCode] 69. Sqrt(x)
    [LeetCode] 258. Add Digits
    [LeetCode] 187. Repeated DNA Sequences
  • 原文地址:https://www.cnblogs.com/yrbbest/p/4438488.html
Copyright © 2011-2022 走看看