zoukankan      html  css  js  c++  java
  • 图-搜索-BFS-DFS-126. 单词接龙 II

    2020-03-19 13:10:35

    问题描述:

    给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:

    1. 每次转换只能改变一个字母。
    2. 转换过程中的中间单词必须是字典中的单词。

    说明:

    • 如果不存在这样的转换序列,返回一个空列表。
    • 所有单词具有相同的长度。
    • 所有单词只由小写字母组成。
    • 字典中不存在重复的单词。
    • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

    示例 1:

    输入:
    beginWord = "hit",
    endWord = "cog",
    wordList = ["hot","dot","dog","lot","log","cog"]
    
    输出:
    [
      ["hit","hot","dot","dog","cog"],
      ["hit","hot","lot","log","cog"]
    ]

    示例 2:

    输入:
    beginWord = "hit"
    endWord = "cog"
    wordList = ["hot","dot","dog","lot","log"]
    
    输出: []
    
    解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。

    问题求解:

    总体思路是先通过BFS搜索最小步数,并且记录BFS树,之后使用DFS得到路径。这里有个地方需要特别注意的是,在构建BFS树的时候,需要在某一层全部遍历结束后再把下一层的一起加入used中,否则会少掉一些上层到下层的边。

    时间复杂度:O(n)

        List<List<String>> res = new ArrayList<>();
        
        Set<String> dict = new HashSet<>();
        Map<String, Set<String>> graph = new HashMap<>();
        
        public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
            for (String s : wordList) dict.add(s);
            if (!dict.contains(endWord)) return res;
            int step = bfs(beginWord, endWord);
            if (step == -1) return res;
            dfs(beginWord, endWord, new ArrayList<>(), step + 1);
            return res;
        }
        
        private void dfs(String begin, String end, List<String> curr, int step) {
            curr.add(begin);
            if (curr.size() == step) {
                if (curr.get(step - 1).equals(end)) res.add(new ArrayList<>(curr));
            }
            else {
                for (String next : graph.get(begin)) {
                    dfs(next, end, curr, step);
                }
            }
            curr.remove(curr.size() - 1);
        }
        
        private int bfs(String begin, String end) {
            boolean flag = false;
            Queue<String> q = new LinkedList<>();
            Set<String> used = new HashSet<>();
            q.add(begin);
            used.add(begin);
            int step = 0;
            while (!q.isEmpty()) {
                if (flag) return step;
                int size = q.size();
                Set<String> layer_used = new HashSet<>();
                for (int k = 0; k < size; k++) {
                    String curr = q.poll();
                    if (!graph.containsKey(curr)) graph.put(curr, new HashSet<>());
                    char[] chs = curr.toCharArray();
                    for (int i = 0; i < chs.length; i++) {
                        char ch = chs[i];
                        for (char c = 'a'; c <= 'z'; c++) {
                            if (c == ch) continue;
                            chs[i] = c;
                            String next = new String(chs);
                            if (next.equals(end)) flag = true;
                            if (!dict.contains(next) || used.contains(next)) continue;
                            graph.get(curr).add(next);
                            q.add(next);
                            layer_used.add(next);
                        }
                        chs[i] = ch;
                    }
                }
                step += 1;
                used.addAll(layer_used);
            }
            return -1;
        }
    

      

  • 相关阅读:
    开博的第一天!
    使用EditText的addTextChangedListener(new TextWatcher())方法
    Activity的四种launchMode
    MySQL数据库
    BaseAdapter中重写getview的心得以及发现convertView回收的机制
    与数据库打交道的Adapter----SimpleCursorAdapter
    [原创] Fragment的添加、移除问题
    Datum Form Goole Android
    app包中的fragment和v4包中的fragment的使用的区别
    LayoutInflater类详解
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12523697.html
Copyright © 2011-2022 走看看