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

    字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:

    序列中第一个单词是 beginWord 。
    序列中最后一个单词是 endWord 。
    每次转换只能改变一个字母。
    转换过程中的中间单词必须是字典 wordList 中的单词。
    给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。

     
    示例 1:

    输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
    输出:5
    解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
    示例 2:

    输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
    输出:0
    解释:endWord "cog" 不在字典中,所以无法进行转换。

    解法一:宽度优先搜索

    class Solution {
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            if (!wordList.contains(endWord)) {
                return 0;
            }
            Set<String> visited = new HashSet<>();
            Queue<String> queue = new LinkedList<>();
            queue.offer(beginWord);
            visited.add(beginWord);
            int count = 0;
            while (queue.size() > 0) {
                int size = queue.size();
                ++count;
                for (int i = 0; i < size; ++i) {
                    String start = queue.poll();
                    for (String s : wordList) {
                        // 已经遍历的不再重复遍历
                        if (visited.contains(s)) {
                            continue;
                        }
                        // 不能转换的直接跳过
                        if (!canConvert(start, s)) {
                            continue;
                        }
                        // 用于调试
                        // System.out.println(count + ": " + start + "->" + s);
                        // 可以转换,并且能转换成 endWord,则返回 count
                        if (s.equals(endWord)) {
                            return count + 1;
                        }
                        // 保存访问过的单词,同时把单词放进队列,用于下一层的访问
                        visited.add(s);
                        queue.offer(s);
                    }
                }
            }
            return 0;
        }
    
        public boolean canConvert(String s1, String s2) {
            if (s1.length() != s2.length()) return false;
            int count = 0;
            for (int i = 0; i < s1.length(); ++i) {
                if (s1.charAt(i) != s2.charAt(i)) {
                    ++count;
                    if (count > 1) {
                        return false;
                    }
                }
            }
            return count == 1;
        }
    }
    
    。

    解法二:双向宽度优先搜索

    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);
            
            // 从两端 BFS 遍历要用的队列
            Queue<String> queue1 = new LinkedList<>();
            Queue<String> queue2 = new LinkedList<>();
            // 两端已经遍历过的节点
            Set<String> visited1 = new HashSet<>();
            Set<String> visited2 = new HashSet<>();
            queue1.offer(beginWord);
            queue2.offer(endWord);
            visited1.add(beginWord);
            visited2.add(endWord);
            
            int count = 0;
            Set<String> allWordSet = new HashSet<>(wordList);
    
            while (!queue1.isEmpty() && !queue2.isEmpty()) {
                count++;
                if (queue1.size() > queue2.size()) {
                    Queue<String> tmp = queue1;
                    queue1 = queue2;
                    queue2 = tmp;
                    Set<String> t = visited1;
                    visited1 = visited2;
                    visited2 = t;
                }
                int size1 = queue1.size();
                while (size1-- > 0) {
                    String s = queue1.poll();
                    char[] chars = s.toCharArray();
                    for (int j = 0; j < s.length(); ++j) {
                        // 保存第j位的原始字符
                        char c0 = chars[j];
                        for (char c = 'a'; c <= 'z'; ++c) {
                            chars[j] = c;
                            String newString = new String(chars);
                            // 已经访问过了,跳过
                            if (visited1.contains(newString)) {
                                continue;
                            }
                            // 两端遍历相遇,结束遍历,返回 count
                            if (visited2.contains(newString)) {
                                return count + 1;
                            }
                            // 如果单词在列表中存在,将其添加到队列,并标记为已访问
                            if (allWordSet.contains(newString)) {
                                queue1.offer(newString);
                                visited1.add(newString);
                            }
                        }
                        // 恢复第j位的原始字符
                        chars[j] = c0;
                    }
                }
            }
            return 0;
        }
    }

    优化牛逼

  • 相关阅读:
    golang的缓冲channel简单使用
    golang协程同步的几种方法
    红黑树原理详解及golang实现
    go路由httprouter中的压缩字典树算法图解及c++实现
    golang编译源代码和交叉编译方法
    cmake使用笔记
    如何用redis设计数据库初探
    muduo学习笔记(六) 多线程的TcpServer
    利用 Blob 处理 node 层返回的二进制文件流字符串并下载文件
    数据量庞大的分页穿梭框实现
  • 原文地址:https://www.cnblogs.com/xiaoming521/p/14932015.html
Copyright © 2011-2022 走看看