lc_bfs_126_findLadders

19 篇文章 0 订阅

题目:单词接龙 II hard

给定两个单词(beginWord 和 endWord)和一个字典 wordList,
找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
    每次转换只能改变一个字母。
    转换后得到的单词必须是字典中的单词。

说明:
    如果不存在这样的转换序列,返回一个空列表。
    所有单词具有相同的长度。
    所有单词只由小写字母组成。
    字典中不存在重复的单词。
    你可以假设 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" 不在字典中,所以不存在符合要求的转换序列。

 

package leetCode.BFS;

import java.util.*;

public class lc_bfs_126_findLadders {

/*
思路:
1.dfs 超时
2.bfs
    直接记录路径path,visited用来记录除了当前访问层外,所有的已经访问过的单词,
    subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词

*/



 /**
     * bfs
     * 直接记录路径path,visited用来记录除了当前访问层外,所有的已经访问过的单词,
     * subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词
     */
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        ArrayDeque<List<String>> pathsQue = new ArrayDeque<>();
        LinkedList<String> path = new LinkedList<>();
        List<List<String>> ans = new LinkedList<>();
        int indexOfendword = wordList.indexOf(endWord);
        if (indexOfendword == -1) {//没有就直接返回,不用查找了
            return ans;
        }
        path.add(beginWord);
        pathsQue.offer(path);
        HashSet<String> dict = new HashSet<>(wordList);
        //用来记录除了当前访问层外,所有的已经访问过的单词,
        // subVisied是记录当前访问层的已访问单词,因为当前层可以重复访问同一个单词
        HashSet<String> visited = new HashSet<>();
        visited.add(beginWord);
        boolean isFound = false;//用来标记在该层已经找到结束单词,不要再遍历下一层了
        while (!pathsQue.isEmpty()) {
            HashSet<String> subVisited = new HashSet<>();
            int size = pathsQue.size();
            for (int j = 0; j < size; j++) {
                List<String> curPath = pathsQue.poll();
                //得到当前路径的末尾单词
                String lastWord = curPath.get(curPath.size() - 1);
                if (lastWord.equals(endWord)) {
                    isFound = true;
                    ans.add(curPath);
                    continue;//不要再扩展路径了,直接检查下一个,该层遍历完就结束
                }

                // 一次性得到所有的下一个的节点
                List<String> neighbors = getNeighbor(lastWord, dict);
                for (String n : neighbors) {
                    //只考虑之前没有出现过的单词,前面层已经出现过的单词再次加入肯定不是最短的,剪枝了
                    if (!visited.contains(n)) {
                        //加入当前单词
                        LinkedList<String> newPath = new LinkedList<>(curPath);
                        newPath.add(n);
                        pathsQue.offer(newPath);
                        //加入当前访问层的已访问的单词,里面的元素和visited里的都不重复
                        subVisited.add(n);
                    }

                }

            }//该层遍历完
            visited.addAll(subVisited);//将当前层的已访问单词加入总的已访问单词
            if (isFound)
                break;//找到后,当前层访问完就不要进行下一层循环,直接跳出返回
        }
        return ans;

    }

//    得到node结点的所有的下一个节点集合
    public List<String> getNeighbor(String node, Set<String> dict) {
        ArrayList<String> res = new ArrayList<String>();
        char chs[] = node.toCharArray();

        for (char ch = 'a'; ch <= 'z'; ch++) {
            for (int i = 0; i < chs.length; i++) {
                if (chs[i] == ch)
                    continue;
                char old_ch = chs[i];
                chs[i] = ch;
                if (dict.contains(String.valueOf(chs))) {
                    res.add(String.valueOf(chs));
                }
                chs[i] = old_ch;
            }

        }
        return res;
    }





    /**
     * 超时 dfs版本
     */
    int minLen = Integer.MAX_VALUE;
    public List<List<String>> findLadders2(String beginWord, String endWord, List<String> wordList) {

        ArrayList<List<String>> ans = new ArrayList<>();
        boolean[] vis = new boolean[wordList.size()];
        ArrayList<String> path = new ArrayList<>();
        path.add(beginWord);
        dfs(beginWord, path, ans, vis, endWord, wordList);
        return ans;
    }


    public void dfs(String cur, List<String> path, List<List<String>> ans, boolean[] vis,
                    String endWord, List<String> wordList) {
        if (cur.equals(endWord)) {
            if (path.size() <= minLen) {
                if (path.size() < minLen)
//                        ans = new ArrayList<>();
                    ans.clear();
                ans.add(new ArrayList<>(path));
                minLen = path.size();
            }
            return;
        }
        if (path.size() >= minLen) {
            return;
        }

        for (int i = 0; i < wordList.size(); i++) {
            String word = wordList.get(i);
            if (!vis[i] && isLike(cur, word)) {
                vis[i] = true;
                path.add(word);
                dfs(word, path, ans, vis, endWord, wordList);
                path.remove(path.size() - 1);
                vis[i] = false;
            }
        }

    }

    public boolean isLike(String a, String b) {
        int count = 0;
        for (int i = 0; i < a.length(); i++) {
            if (a.charAt(i) != b.charAt(i)) {
                count++;
                if (count > 1)
                    return false;
            }

        }
        return true;
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值