leetcode 126. 单词接龙 II

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

每次转换只能改变一个字母。

转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回一个空列表。

  • 所有单词具有相同的长度。

  • 所有单词只由小写字母组成。

  • 字典中不存在重复的单词。

  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

 

题解:

1.两个单词、一个字典

2.从 beginWord 到 endWord 的最短转换序列,不存在返回空

3.每次转换只能改变一个字母

4.转换的中间单词在字典中

 

示例 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" 不在字典中,所以不存在符合要求的转换序列。

 

解题思路:

  • 先把开始单词和目标单词添加到容器中方便处理

  • 对每次查找转换序列,建立一个“链表”(用map映射),map里的key和value值分别对应前一个单词和转换的后一个单词

  • 递归上一个过程,如果在最后在字典里找到了这个目标单词,说明存在一条可达路径

  • 直到存在后,递归搜索这个单词路径,中间单词都记录下来作为返回

  • 如果判断不存在这个路径,直接返回空列表

Java题解:

class Solution {

    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList){

        List<List<String>> res = new ArrayList<>();//返回一个二维列表

        Set<String> words = new HashSet<>(wordList);//字典去重

        if (!words.contains(endWord)) {

            return res;}// 字典中没有目标单词,不能转换

 

        // 存放关系:每个单词可达的下层单词

        Map<String, List<String>> mapTree = new HashMap<>();

        Set<String> begin = new HashSet<>(), end = new HashSet<>();

        begin.add(beginWord); //字符输入加到容器里

        end.add(endWord); //目标字符加到容器里

        if (buildTree(words, begin, end, mapTree, true)) {//如果有一条可达路径

            //递归把中间单词加到结果里

            dfs(res, mapTree, beginWord, endWord, new LinkedList<>());}

        return res;}

    // 双向BFS,构建每个单词的层级对应关系

    private boolean buildTree(Set<String> words, Set<String> begin, Set<String> end, Map<String, List<String>> mapTree, boolean isFront){

        if (begin.size() == 0) {

            return false; }

        // 始终以少的进行探索

        if (begin.size() > end.size()) {

            return buildTree(words, end, begin, mapTree, !isFront); }

        // 在已访问的单词集合中去除

        words.removeAll(begin);

        // 标记本层是否已到达目标单词

        boolean isMeet = false;

        // 记录本层所访问的单词

        Set<String> nextLevel = new HashSet<>();

        for (String word : begin) {

            char[] chars = word.toCharArray();

            for (int i = 0; i < chars.length; i++) {

                char temp = chars[i];

                for (char ch = 'a'; ch <= 'z'; ch++) {

                    chars[i] = ch;//尝试替换每个字母

                    String str = String.valueOf(chars); //替换完转成String

                    if (words.contains(str)) { //如果字典中有替换完的单词

                        nextLevel.add(str); //把中间单词记录下来

                        // 根据访问顺序,添加层级对应关系:始终保持从上层到下层的存储关系

                        // true: 从上往下探索:word -> str

                        // false: 从下往上探索:str -> word(查找到的 str 是 word 上层的单词)

                        String key = isFront ? word : str;

                        String nextWord = isFront ? str : word;

                        // 判断是否遇见目标单词

                        if (end.contains(str)) {//end里是目标单词

                            isMeet = true;   }//如果当前中间过程单词是目标单词,停止

 

                        if (!mapTree.containsKey(key)) {//存储关系,没有key就添加

                            mapTree.put(key, new ArrayList<>());}

                        //添加key对应的value值,key上一个中间单词,value为下一个单词

                        mapTree.get(key).add(nextWord);}}

                chars[i] = temp;  } }//找到中间过程单词,把开始单词还原

 

        if (isMeet) {//到达目标单词,则有一条路径从开始单词到达目标单词

            return true; }//返回true

 

        return buildTree(words, nextLevel, end, mapTree, isFront);}

    // DFS: 组合路径

    private void dfs (List<List<String>> res, Map<String, List<String>> mapTree, String beginWord, String endWord, LinkedList<String> list) {

        list.add(beginWord);

        if (beginWord.equals(endWord)) {//开始单词和目标单词相同

            res.add(new ArrayList<>(list));}//返回该单词

 

        //map中key和value分别对应前后单词

        if (mapTree.containsKey(beginWord)) {//map中有开始单词的key

            for (String word : mapTree.get(beginWord)) {//递归把value里的中间单词

                dfs(res, mapTree, word, endWord, list); }}//添加到结果集里

        list.removeLast();}}

Debug结果:

更多题解移步公众号免费获取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值