zoukankan      html  css  js  c++  java
  • LeetCode127. 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:
    1. Only one letter can be changed at a time.
    2. 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.
     
     

     
    一刷:
    思路:非常妙的一个题。开始并没有想到要用图的BFS,但是题目的暗示:求最短变换路径的长度,其实就可以转换成求图的最短路径长度。可以将每个单词视为一个节点,然后如果可以相互转换的则认为在图中是相连的。
     
    用bfs解决最短路径有三个关键点:
    • 如何找到当前点的相邻点:方法一是直接从集合里搜,时间复杂度是n*w,n是集合中单词个数,w是每个单词的长度,当集合里有成千上万个单词时这显然不是一种好方法;方法二是将当前单词的每个字母都用a-z中的字母代替,看集合中有没有代替后的这个单词,如果有则加入相邻点的list。
    • 如何判重:即访问过的点不能再访问了。
    • 找到节点后如何backtracking找到经过的路径。
     public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            HashSet<String> dict=new HashSet<String>();
            if(wordList.size()==0 || wordList==null){
                return 0;
            }
            for(String s:wordList){
                dict.add(s);
            }
            HashSet<String> visited=new HashSet<String>();
            Queue<String> queue=new LinkedList<String>();
    
            if(beginWord.equals(endWord)){
                return 1;
            }
            int pathLength=1;
    
            queue.add(beginWord);
            visited.add(beginWord);
    
            while(!queue.isEmpty()){
                int size=queue.size();
                pathLength++;
                for(int i=0;i<size;i++){
                    String word=queue.poll();
                    for(String nextWord:getNextWord(word,dict)){
                       if(!visited.contains(nextWord)){
                           if(nextWord.equals(endWord)){
                               return pathLength;
                           }
                           visited.add(nextWord);
                           queue.add(nextWord);
                       }
                   }
                }
    
            }
            return 0;
        }
        private List<String> getNextWord(String word,HashSet<String> dict){
            List<String> ret=new ArrayList<String>();
            for(char c='a';c<='z';c++){
                for(int i=0;i<word.length();i++){
                    if(c==word.charAt(i)){
                        continue;
                    }
                    String nextWord=wordReplace(word,i,c);
                    if(dict.contains(nextWord)){
                        ret.add(nextWord);
                    }
                }
            }
            return ret;
        }
        private String wordReplace(String word,int index,char c){
            char[] newWord=word.toCharArray();
            newWord[index]=c;
            return new String(newWord);
        }
    View Code

    二刷:

    之前的单向BFS已经超时了,于是参考了双向BFS解法

    双向BFS,复杂度更低,思想就是两个SET, 交替扩展,直到两个set有元素重合,即有一条可通路

    /**
     * 双向BFS,复杂度更低,思想就是两个SET, 交替扩展,直到两个set有元素重合,即有一条可通路
     */
    
    public class WordLadder {
    
        public int ladderLength(String beginWord, String endWord, List<String> wordList) {
            int step = 0;
            Set<String> s1 = new HashSet<>();
            Set<String> s2 = new HashSet<>();
            Set<String> dict = new HashSet<>();
            if (!wordList.contains(endWord)) return step;
            for (String word : wordList) dict.add(word);
            s1.add(beginWord);
            s2.add(endWord);
            while (!s1.isEmpty() && !s2.isEmpty()) {
                step++;
                if (s1.size() > s2.size()) swap(s1, s2); //每次都扩展容量小的那个set
                Set<String> tmpSet = new HashSet<>();
                for (String word : s1) {
                    for (String newWord : getNextWord(word)) {
                        if (s2.contains(newWord)) return step + 1;
                        if (!dict.contains(newWord)) continue;
                        dict.remove(newWord);
                        tmpSet.add(newWord);
                    }
                }
                s1 = tmpSet;
            }
            return 0;
        }
    
        private List<String> getNextWord(String word) {
            List<String> res = new ArrayList<>();
            res.add(word);
            for (int i = 0; i < word.length(); i++) {
                for (char c = 'a'; c <= 'z'; c++) {
                    String newWord = replaceWord(word, i, c);
                    res.add(newWord);
                }
            }
            return res;
        }
    
        private void swap(Object o1, Object o2) {
            Object tmp = o1;
            o1 = o2;
            o2 = tmp;
        }
    
        private String replaceWord(String word, int index, char c) {
            char[] newWord = word.toCharArray();
            newWord[index] = c;
            return new String(newWord);
        }
    
        public static void main(String[] args) {
            WordLadder wordLadder = new WordLadder();
            String[] strings = {"hot","dog"};
            System.out.println(wordLadder.ladderLength("hot", "dog", Arrays.asList(strings)));
        }
    }
    View Code
  • 相关阅读:
    iOS强引用和弱引用
    HTTP和Socket的区别
    iOS日期加减
    iOS判断日期A是否在日期B到日期C之间
    分布式锁与实现(一)——基于Redis实现 【比较靠谱】
    Redisson实现分布式锁
    Redisson分布式锁实现
    从redis中取值如果不存在设置值,使用Redisson分布式锁【我】以及不使用锁的方式
    redisson整合spring
    如何优雅地用Redis实现分布式锁?
  • 原文地址:https://www.cnblogs.com/shawshawwan/p/9221096.html
Copyright © 2011-2022 走看看