leetcode127 单词接龙

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

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。

说明:

如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例 1:

输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]

输出: 5

解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。

示例 2:

输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]

输出: 0

解释: endWord “cog” 不在字典中,所以无法进行转换。


解法

  1. 深度优先遍历 重复量太大 超时
  2. 广度优先遍历 利用队列存储每一层数据 一层一层 其中判断是否为相差一个字母的单词 采用的是遍历wordlist分别比较的方法 此方法超时 通过29/39
class Solution {
   public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Queue<String> queue = new LinkedList<>();
        queue.offer(beginWord);
        HashSet<String> set = new HashSet<>();
        set.add(beginWord);
        int path = 0;
        List<String> list = new ArrayList<>();
        while (!queue.isEmpty()){
            path++;
            list.clear();
            while (!queue.isEmpty()){
                list.add(queue.poll());
            }
            String tmpStr;
            for (int i = 0;i<list.size();i++){
                tmpStr = list.get(i);
                if(tmpStr.equals(endWord)) return path;
                set.add(tmpStr);
                for (String str:wordList){
                    if(checkOne(tmpStr,str)){
                        if(!set.contains(str)){
                            queue.offer(str);
                        }
                    }
                }
            }
        }
        return 0;
    }


    private boolean checkOne(String beginWord,String endWord){
        int result = 0;
        for (int i = 0;i<beginWord.length();i++){
            if(beginWord.charAt(i)!=endWord.charAt(i)){
                result++;
            }
            if(result>1) break;
        }
        return result>1?false:true;
    }

}
  1. 解法3主要针对2中 判断是否为相差一个字母的单词 采用的是遍历wordlist进行改进
    改为//采用hash的方式 用set存储单词表 替换当前节点的单词current每个字符(从a~z),然后看看替换过后的单词是否在单词表中
    通过 32/39 有提高 超时
class Solution {
   public int ladderLength(String beginWord, String endWord, List<String> wordList) {
        Queue<String> queue = new LinkedList<>();
        queue.offer(beginWord);

        HashSet<String> hasVisitedSet = new HashSet<>();
        hasVisitedSet.add(beginWord);

        HashSet<String> wordListSet = new HashSet<>(wordList);

        int path = 0;
        int size;
        while (!queue.isEmpty()){
            path++;
            size = queue.size();
            String tmpStr;
            for (int i = 0;i<size;i++){
                tmpStr = queue.poll();
                if(tmpStr.equals(endWord)) return path;
                hasVisitedSet.add(tmpStr);
                checkOneHash(tmpStr,wordListSet,hasVisitedSet,queue);
            }
        }
        return 0;
    }

    //采用hash的方式 用set存储单词表  替换当前节点的单词current每个字符(从a~z),然后看看替换过后的单词是否在单词表中
    private void checkOneHash(String beginWord,HashSet<String> wordListSet,HashSet<String> hasVisitedSet,Queue<String> queue){
        char[] chars = beginWord.toCharArray();
        for (int i = 0;i<beginWord.length();i++){
            for (int j = 'a';j<'z'+1;j++){
                chars[i] = (char) j;
                String str = new String(chars);
                if(wordListSet.contains(str) && !hasVisitedSet.contains(str)){
                    queue.offer(str);
                }
                chars[i] = beginWord.charAt(i);
            }
        }
    }
}
  1. 解法3中使用队列来存储当前层数据 判断当前层中是否包含endWord的时候采用遍历队列中的数据 负责读为o(n) 当单词数量比较大时 这是超时的主要原因
    解法4则采用set替代队列存储当前层数据 降低时间复杂度
    全部通过
class Solution {
    public int ladderLength(String beginWord, String endWord, List<String> wordList) {

        HashSet<String> set = new HashSet<>();
        set.add(beginWord);


        HashSet<String> wordListSet = new HashSet<>(wordList);


        int path = 0;
        while (!set.contains(endWord)){
            path++;
            HashSet<String> tmpSet = new HashSet<>();
            for (String tmpStr : set){
                wordListSet.remove(tmpStr);
                checkOneHash(tmpStr,wordListSet,tmpSet);
            }
            if(tmpSet.size()==0) return 0;
            set = tmpSet;
        }
        return path+1;
    }

    //采用hash的方式 用set存储单词表  替换当前节点的单词current每个字符(从a~z),然后看看替换过后的单词是否在单词表中
    private void checkOneHash(String beginWord,HashSet<String> wordListSet,HashSet<String> tmpSet){
        char[] chars = beginWord.toCharArray();
        for (int i = 0;i<beginWord.length();i++){
            for (int j = 'a';j<'z'+1;j++){
                chars[i] = (char) j;
                String str = new String(chars);
                if(wordListSet.contains(str)){
                    tmpSet.add(str);
                }
                chars[i] = beginWord.charAt(i);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_37129669/article/details/84930332