127. Word Ladder

输入:beginword,endword,wordList
输出:从beginWord,到endWord,需要几步。
规则:每次只变一个字母
分析:(原文)输入是 beginWord 和 endWord。我们可以让他们分别代表图的 开始节点 startNode 和结束节点endNode。我们需要使用一些中间节点从开始节点走到结束节点。这些中间节点就是wordList中的值。每走一步的条件是:当前节点只能修改一个字母。
 我们会用一个无向无权重的图来实现,每个节点是一个单词。如果两个节点只差一个字母,那他们之间就有一条边。这个问题就可以归结为从开始节点到结束节点,找到一条最短路径。所以问题可以用BFS解决。
 这里其中一个重要的问题是如何找到一个节点的邻节点。对任意给定一个词,为了高效地找到其邻节点我们需要做一些预处理工作。预处理工作是把字母替换为一个非字母,例如*.例如 hot可以处理为 “*ot”,“h*t”,“ho*”。这样的预处理之后,我们会得到一个单词可以变形的一般状态。
 例如 dog有一个变形是 d*g,dig也有一个变形是d*g。这样可以很轻易地找到一个词的变形的词。
 预处理步骤能够让我们扎到wordList中任何单词的变形,可以比较轻松容易地找到单词的邻节点。
 方法1:
 1 对wordList做预处理工作,存在map中。key是所有单词的变形,value是符合这个变形的单词。
 2 将<beiginWord,1>放入队列中。1代表了当前节点所在的层次。我们需要返回endWord所在的层次,这也是从beginWord到endWord的最短路径长度。
 3 为了防止死循环,需要一个visited数组,记录已经处理过的节点。
 4 从队列头拿到一个元素currentWord。
 5 找到currentWord的所有变形,根据变形从map中找到邻节点。
 6 将这些邻节点加入到队列中。放入的时候每个单词word的层次是需要加1的: <word,level+1>加入到队列。
 7 如果我们看到了endNode,返回它的层次。

public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Map<String,List<String>> allComboDict = new HashMap<String,List<String>>();
        int wordLen = beginWord.length();
        for(String word : wordList){
            for(int i=0;i<wordLen;i++){
                String format = word.substring(0,i)+"*"+word.substring(i+1,wordLen);
                List<String> list = allComboDict.getOrDefault(format,new ArrayList<String>());
                list.add(word);
                allComboDict.put(format,list);
            }
        }

        Queue<Pair<String,Integer>> queue = new LinkedList<Pair<String,Integer>>();
        queue.offer(new Pair<>(beginWord,1));
        Map<String, Boolean> visited = new  HashMap<String,Boolean>();
        visited.put(beginWord,true);
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i=0;i<size;i++){
                Pair<String,Integer> node = queue.poll();
                String word = node.getKey();
                int level = node.getValue();
                for(int j=0;j<wordLen;j++){
                    String format = word.substring(0,j)+"*"+word.substring(j+1,wordLen);
                    for(String nextWord : allComboDict.getOrDefault(format,new ArrayList<String>())){
                        if(nextWord.equals(endWord)) {
                            return level+1;
                        }
                        if(!visited.containsKey(nextWord)){
                            visited.put(nextWord,true);
                            queue.offer(new Pair<>(nextWord,level+1));
                        }

                    }
                }
            }
        }

        return 0;
    }

这个解决方法很精彩的地方时:先找到每个词的变形format,并且将format作为key。而我的思维中一直是想把词作为key,将邻节点列表作为value,放入map中。我自己也有实现。但是找邻节点的方式就是每次变换。耗时巨慢。
 之前在我的思维中用BFS、DFS遍历图都应该能得到结果。如果用DFS的话需要遍历每条路径,以找到最短的那条。所以DFS不太方便。
 代码
 代码
 方法2:在上面的实现方法中,单向BFS,搜索需要的空间会随着层次的增加空间越来越多。想象你的访问一颗完全二叉树,空间会以2的指数增加。如果使用双向BFS,每个方向遍历的层次会减半,搜索空间会降低。
 代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值