zoukankan      html  css  js  c++  java
  • LeetCode127. 单词接龙

    为什么要用BFS?

      无向图求最短路,广搜最为合适,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。

      本题是一个无向图,需要用标记位,标记着节点是否走过,否则就会死循环!

    ☆☆☆方法1:BFS

    ☆☆☆☆方法2:双向BFS,减少搜索空间大小。

      BFS的搜索空间大小依赖于每层节点的分支数量。每次都从中间结果少的那一端出发,这样就能剪枝掉很多不必要的搜索过程。

      注意:如果遇到了另一个visited里有过的结点,那么说明可以连接。

    关于单词转换判断

      思路1:遍历所有候选单词,判断当前单词是否可以转换成这个候选单词。

      思路2:因为单词是由 a~z 这有限数量的字符组成的,可以遍历当前单词能转换成的所有单词,判断其是否包含在候选单词中。候选单词用 HashSet 保存,可以大大提高判断包含关系的性能。

    代码1.1:BFS(耗时523ms)

    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            if (!wordList.contains(endWord)) {
                return 0;
            }
    
            Queue<String> queue = new LinkedList<>();
            boolean[] visited = new boolean[wordList.size()];
            queue.offer(beginWord);
            int idx = wordList.indexOf(beginWord);
            if (idx != -1) {
                visited[idx] = true;
            }
    
            int level = 1; // 初始单词也算一次
            while (!queue.isEmpty()) {
                int size = queue.size();
                level ++;
                for (int i = 0; i < size; i++) {
                    String cur = queue.poll();
                    for (int j = 0; j < wordList.size(); j++) {
                        if (visited[j]) continue;
                        String s = wordList.get(j);
                        if (canConvert(cur,s)) {
                            if (s.equals(endWord)) {
                                return level;
                            }
                            queue.offer(s);
                            visited[j] = true;
                        }
                    }
    
                }
            }
            return 0;
        }
        private boolean canConvert(String cur, String s) {
            int diff = 0;
            for (int i = 0; i < cur.length(); i++) {
                if (cur.charAt(i) != s.charAt(i)) {
                    diff ++;
                    if (diff > 1) break;
                }
            }
            return diff == 1;
        }
    }

    代码1.2:BFS + 优化单词转换判断(耗时76ms)

    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            // 把字典中的单词放入到set中,主要是为了方便查询
            HashSet<String> dictSet = new HashSet<>(wordList);
            if (dictSet.size() == 0 || !dictSet.contains(endWord)) {
                return 0;
            }
            dictSet.remove(beginWord);
    
            Queue<String> queue = new LinkedList<>();
            HashSet<String> visited = new HashSet<>();
            queue.offer(beginWord);
            visited.add(beginWord);
    
            int level = 1;
            while (!queue.isEmpty()) {
                int size = queue.size();
                level ++;
                for (int i = 0; i < size; i++) {
                    String cur = queue.poll();
                    char[] chars = cur.toCharArray();
                    //修改单词的每一个字符,成为新的单词
                    for (int j = 0; j < cur.length(); j++) {
                        // 先保存再恢复
                        char temp = chars[j];
                        for (char k = 'a'; k <= 'z'; k++) {
                            if (k == temp) continue;
                            chars[j] = k;
                            String newWord = String.valueOf(chars);
                            if (dictSet.contains(newWord) && !visited.contains(newWord)) {
                                if (newWord.equals(endWord)) {
                                    return level;
                                }
                                queue.offer(newWord);
                                visited.add(newWord);
                            }
                        }
                        chars[j] = temp;
                    }
    
                }
            }
            return 0;
        }
    }

    代码2.1:双向BFS(耗时128ms)

    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            int end = wordList.indexOf(endWord);
            if (end == -1) {
                return 0;
            }
            wordList.add(beginWord);
            int start = wordList.size() - 1;
    
            Queue<Integer> queue1 = new LinkedList<>();
            Queue<Integer> queue2 = new LinkedList<>();
            Set<Integer> visited1 = new HashSet<>();
            Set<Integer> visited2 = new HashSet<>();
            queue1.offer(start);
            queue2.offer(end);
            visited1.add(start);
            visited2.add(end);
    
            int level = 1;
            while (!queue1.isEmpty() && !queue2.isEmpty()) {
                if (queue1.size() > queue2.size()) {
                    Queue<Integer> tempQueue = queue1;
                    queue1 = queue2;
                    queue2 = tempQueue;
                    Set<Integer> tempSet = visited1;
                    visited1 = visited2;
                    visited2 = tempSet;
                }
                int size1 = queue1.size();
                level ++;
                for (int i = 0; i < size1; i++) {
                    String cur = wordList.get(queue1.poll());
                    for (int j = 0; j < wordList.size(); j++) {
                        if (visited1.contains(j)) continue;
                        String s = wordList.get(j);
                        if (canConvert(cur, s)) {
                            if (visited2.contains(j)) { // 相遇,说明可以连接
                                return level;
                            }
                            queue1.offer(j);
                            visited1.add(j);
                        }
                    }
                }
    
            }
            return 0;
        }
        private boolean canConvert(String cur, String s) {
            int diff = 0;
            for (int i = 0; i < cur.length(); i++) {
                if (cur.charAt(i) != s.charAt(i)) {
                    diff ++;
                    if (diff > 1) break;
                }
            }
            return diff == 1;
        }
    }

    代码2.2:双向BFS + 优化单词转换判断(耗时14ms)

    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            Set<String> dictSet = new HashSet<>(wordList);
            if (dictSet.size() == 0 || !dictSet.contains(endWord)) return 0;
    
            Queue<String> queue1 = new LinkedList<>();
            Queue<String> queue2 = new LinkedList<>();
            Set<String> visited1 = new HashSet<>();
            Set<String> visited2 = new HashSet<>();
            queue1.offer(beginWord);
            visited1.add(beginWord);
            queue2.offer(endWord);
            visited2.add(endWord);
    
            int level = 1;
            while (!queue1.isEmpty() && !queue2.isEmpty()) {
                if (queue1.size() > queue2.size()) {
                    Queue<String> tempQueue = queue1;
                    queue1 = queue2;
                    queue2 = tempQueue;
                    Set<String> tempSet = visited1;
                    visited1 = visited2;
                    visited2 = tempSet;
                }
                int size1 = queue1.size();
                level ++;
                for (int i = 0; i < size1; i++) {
                    String cur = queue1.poll();
                    char[] chars = cur.toCharArray();
                    for (int j = 0; j < cur.length(); j++) {
                        char temp = chars[j];
                        for (char k = 'a'; k <= 'z'; k++) {
                            if (k == temp) continue;
                            chars[j] = k;
                            String newWord = String.valueOf(chars);
                            if (dictSet.contains(newWord) && !visited1.contains(newWord)) {
                                if (visited2.contains(newWord)) {  // 两端遍历相遇
                                    return level;
                                }
                                queue1.offer(newWord);
                                visited1.add(newWord);
                            }
                        }
                        chars[j] = temp; // 恢复第j位的原始字符
                    }
    
                }
            }
            return 0;
        }
    }

     

    优化过程参考:

      算法实现和优化(Java 双向 BFS,23ms)

  • 相关阅读:
    Python split分割字符串
    test markdown
    Python 数字格式转换
    Python 字符串改变
    Python axis的含义
    python 第三方库
    Spark快速入门
    vim快捷键
    Hadoop HDFS负载均衡
    YARN DistributedShell源码分析与修改
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/14161668.html
Copyright © 2011-2022 走看看