LeetCode:127. Word Ladder

题目要求大体如下:

Given two words (beginWord and endWord), and a dictionary’s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

Only one letter can be changed at a time.
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,

Given:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
As one shortest transformation is “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
return its length 5.

Note:
Return 0 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the word list.
You may assume beginWord and endWord are non-empty and are not the same.

UPDATE (2017/1/20):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.

大体的要求就是通过每次只能改变一个字母,把初始单词改变成最终的单词,但是只能从给定的单词列表中选取,给出最短的路径。

一.我的解法

这个题目看了几遍之后,发现是个求最短路径的搜图,即无向图中原点到要求点的路径最短,因为题中没有提到权重,所以默认点与点之间的路径权重都为1。故可以将给出的例子抽象成如下的无向图。
这里写图片描述
如图所示,我们可以看见因为每次单词变化只能改变一个字母,所以hit的邻点就是hot,依次类推画出无向图。因为题目要求给出最短搜索路径,那么最好的办法就是BFS搜图,然后给出长度。要注意的是因为无向图,所以进行搜索中会将已遍历过的加入队列从而带来干扰,一个好的解决办法就是加入队列的同时,将原来这个单词从集合中删去。这样就排除了干扰。
这里写图片描述
这是第一次循环后,将列表中的hot加入队列中,并删去其在wordList
这里写图片描述
这是第二次循环后,将dotlot加入队列,并在wordList中删去它们。
这里写图片描述
以此类推,最终可以得到cog在队列中,此时便是最短路径。
时间复杂度为O(M*N),
其中M代表的是单词的长度;
N代表的是整个路径的长度

class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Set<String> wordSet=new HashSet<>(wordList);
        Queue<String> visited=new LinkedList<>();
        visited.offer(beginWord);
        int len=1;
        while(!visited.isEmpty()){
            for(int j=visited.size();j>0;j--){
                String word=visited.poll();
                if(word.equals(endWord)) return len;
                for(int i=0;i<word.length();i++){
                    char[] charWord=word.toCharArray();
                    for(char c='a';c<='z';c++){
                        char temp=charWord[i];
                        charWord[i]=c;
                        String changedWord=String.valueOf(charWord);
                        if(wordSet.contains(changedWord))
                        {
                            visited.offer(changedWord);
                            wordSet.remove(changedWord);
                        }
                        else
                            charWord[i]=temp;
                    }
                }
            }
            len++;
            }
                return 0;
        }
}

二.扩展

其实上面的解法效率并不高,因为从头到尾搜图太耗时间。所以参考了leetcode的discussion的解法后,发现其实可以选择双向搜图,即不仅是从beginWord开始搜图,同时也从endWord搜图。如果两个方向搜到同一个单词,就说明该路径就是最短路径。至于为什么双向搜图比单向更快,是因为单向搜索树建的太深,会导致循环的时候时间会指数增长,所以每次选择最小的搜索树进行就会缩小每次循环的时间,虽然总的深度不变,但是因为每次是较小的树进行BFS遍历,就会效率变高许多。时间复杂度应该是O(M*N/2),其中M代表的是单词的长度;
N代表的是整个路径的长度
这个是原地址:
https://discuss.leetcode.com/topic/29303/two-end-bfs-in-java-31ms


class Solution{
    public int ladderLength(String beginWord,String endWord,List<String> wordList){
        Set<String> head=new HashSet<>(),tail=new HashSet<>(),wordSet=new HashSet<>(wordList);
        Set<String> visited=new HashSet<>();
        if(!wordSet.contains(endWord)) return 0;
        head.add(beginWord);
        tail.add(endWord);
        int len=2;
        while(!head.isEmpty()&&!tail.isEmpty()){
            if(head.size()>tail.size())
            {
                Set<String> temp=head;
                head=tail;
                tail=temp;
            }
            Set<String> t=new HashSet<>();
            for(String word:head){
                char[] charWord=word.toCharArray();
                for(int i=0;i<charWord.length;i++){
                    for(char c='a';c<='z';c++){
                        char temp=charWord[i];
                        charWord[i]=c;
                        String changedWord=String.valueOf(charWord);
                        if(tail.contains(changedWord)) return len;
                        if(!visited.contains(changedWord)&&wordSet.contains(changedWord)){
                            t.add(changedWord);
                            visited.add(changedWord);
                        }
                        charWord[i]=temp;
                    }
                }
            }
            head=t;
            len++;
        }
        return 0;
    }
}

如果有什么错误的地方,请务必让我知道,我会积极改进学习的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值