LeetCode:126Word Ladder II

problem

LeetCode 126

Given two words (beginWord and endWord), and a dictionary’s word list, find all shortest transformation sequence(s) 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.

solution

思路过程

  • 从一个单词转换到另外一个单词,并且是最短的路径
  • 每次只能转换一个字母,有些单词不能一次性转换完成,还有些需要一些单词来中转,我怎么能确定中转呢?怎么来做到最小呢?是不是从不同的位置开始换,结果也会不一样呢?
  • 用最暴力的方法,从第一个字母开始,如果能找到替换成endword的中间单词在里面,就直接替换,如果找不到呢?中间可能有好几层替换,,,,
  • 不行,可能行太多了,这样下来真的不行
  • 放弃,看解答
  • 大神的解答就是牛逼,我看都花了好久
方法一:bfs+dfs->单向遍历

代码

Java

class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        Set<String> wordSet = new HashSet<>(wordList);//这里用hashset,一是为了减少重复,二是为了快速查找
        List<List<String>> res = new ArrayList<>();
        if (!wordSet.contains(endWord) || wordSet.size() == 0) {
            return res;
        }
        Map<String, Set<String>> Make_graphic = new HashMap<>();
//通过bfs找到的都是最短就能到达的
        boolean found = bfs(beginWord, endWord, wordSet, Make_graphic);
        System.out.print(Make_graphic);
        if (found) {
            Stack<String> path = new Stack<>();
            path.push(beginWord);
            dfs(beginWord, endWord, Make_graphic, path, res);
        }
        return res;

    }

    public boolean bfs(String beginWord, String endWord, Set<String> wordSet, Map<String, Set<String>> Make_Graphic) {
        Queue<String> queue = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        queue.offer(beginWord);
        visited.add(beginWord);
        boolean found = false;
        int WordLength = beginWord.length();
        // 这里要用nextLevelVisited来暂时缓存已经被访问过的,因为不这样做,下一层的本可以再访问一次,就访问不了了。比如有两条路径都指向endword,第一跳访问后endword就被访问过了,那么下一条路径就没办法形成了
        Set<String> nextLevelVisited=new HashSet<>();
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                String CurrentWord = queue.poll();
                char[] charArray = CurrentWord.toCharArray();
                for (int j = 0; j < WordLength; j++) {
                    char originalChar = charArray[j];
                    for (char k = 'a'; k <= 'z'; k++) {
                        charArray[j] = k;
                        if (charArray[j] == originalChar) {
                            continue;
                        }
                        String nextWord = new String(charArray);
                        if (wordSet.contains(nextWord)) {
                            if (!visited.contains(nextWord)) {
                                if (nextWord.equals(endWord)) {
                                    found = true;
                                }
                                nextLevelVisited.add(nextWord);
                                queue.offer(nextWord);
//                                visited.add(nextWord);
                                Make_Graphic.computeIfAbsent(CurrentWord, a -> new HashSet<>());
                                Make_Graphic.get(CurrentWord).add(nextWord);
                            }
                        }
                    }
                    charArray[j] = originalChar;
                }
            }
            if (found) {
                break;
            }
            visited.addAll(nextLevelVisited);
            nextLevelVisited.clear();
        }
        return found;
    }

    public void dfs(String BeginWord, String EndWord, Map<String, Set<String>> graphic, Stack<String> path, List<List<String>> res) {
        if (BeginWord.equals(EndWord)) {
            res.add(new ArrayList<>(path));
        }
        if (!graphic.containsKey(BeginWord)) {
            return;
        }
        Set<String> NextWord = graphic.get(BeginWord);
        for (String next : NextWord) {
            path.push(next);
            dfs(next, EndWord, graphic, path, res);
            path.pop();
        }
    }
}
方法二:bfs+dfs->双向遍历

对于代码中自己或许可以有些帮助的给了一些注释,
运行结果快了好多好多呀,厉害d=====( ̄▽ ̄*)b

代码

python

class Solution:
    def addToGraphic(self, word, changeWord, graphic, forward):
        if not forward:
            temp = word
            word = changeWord
            changeWord = temp
        if word not in graphic:
            graphic[word] = {changeWord}
        else:
            graphic[word].add(changeWord)

    def bfs(self, beginWord, endWord, graphic, wordList):
        found = False
        forward = True
        forward_search = {beginWord}
        back_search = {endWord}
        visited = {beginWord, endWord}
        word_length = len(beginWord)
        alpha26 = set('abcdefghijklmnopqrstuvwxyz')
        while forward_search and back_search:
            if len(forward_search) > len(back_search):
                temp = forward_search
                forward_search = back_search
                back_search = temp
                forward = not forward
            next_visited = set()
            for word in forward_search:
                for i in range(word_length):
                    for j in alpha26:
                        if j == word[i]:
                            continue
                        change_word = word[0:i] + j + word[i + 1:]
                        if change_word in wordList:
                            if change_word in back_search:
                                found = True
                                self.addToGraphic(word, change_word, graphic, forward)
                            if change_word not in visited:
                                next_visited.add(change_word)
                                self.addToGraphic(word, change_word, graphic, forward)
            if found:
                return found
            visited.update(next_visited)
            forward_search = next_visited
        return found

    def dfs(self, beginword, endword, graphic, res, path):
        if beginword == endword:
            # 这里如果直接添加,当path改变时,res也会改变,因为指向的是同一块地址,所以res需要添加path重新复制的一块
            # res.append(path)
            res.append(path.copy())
            # print(res,1)
        if beginword not in graphic:
            return
        for word in graphic[beginword]:
            # print(path)
            path.append(word)
            self.dfs(word, endword, graphic, res, path)
            path.pop()

    def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
        if not wordList or endWord not in wordList:
            return []
        wordList = set(wordList)
        res = []
        graphic =dict()
        # 这里只写了双向查找的
        if (self.bfs(beginWord, endWord, graphic, wordList)):
            print(graphic)
            path = [beginWord]
            res=[]
            self.dfs(beginWord, endWord, graphic, res, path)
            # print(res,2)
            return res
        return []

Java

class Solution {
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        Set<String> wordSet = new HashSet<>(wordList);//这里用hashset,一是为了减少重复,二是为了快速查找
        List<List<String>> res = new ArrayList<>();
        if (!wordSet.contains(endWord) || wordSet.size() == 0) {
            return res;
        }
        Map<String, Set<String>> Make_graphic = new HashMap<>();
//通过bfs找到的都是最短就能到达的,现在要从两个方向来,其实也是形成一样的图,但是,现在就得判断是哪一个方向了
        boolean found = bfs(beginWord, endWord, wordSet, Make_graphic);
        System.out.print(Make_graphic);
        if (found) {
            Stack<String> path = new Stack<>();
            path.push(beginWord);
            dfs(beginWord, endWord, Make_graphic, path, res);
        }
        return res;

    }

    public boolean bfs(String beginWord, String endWord, Set<String> wordSet, Map<String, Set<String>> Make_Graphic) {
        Set<String> BeginVisted = new HashSet<>();
        Set<String> EndVisted = new HashSet<>();
        Set<String> visited = new HashSet<>();
        BeginVisted.add(beginWord);
        EndVisted.add(endWord);
        visited.add(beginWord);
        visited.add(endWord);
        boolean forward=true;
        boolean found = false;
        int WordLength = beginWord.length();
        // 这里要用nextLevelVisited来暂时缓存已经被访问过的,因为不这样做,下一层的本可以再访问一次,就访问不了了。比如有两条路径都指向endword,第一跳访问后endword就被访问过了,那么下一条路径就没办法形成了
        while (!BeginVisted.isEmpty() && !EndVisted.isEmpty()) {
        Set<String> nextLevelVisited=new HashSet<>();
            if(BeginVisted.size()>EndVisted.size()){
                Set<String> temp=BeginVisted;
                BeginVisted=EndVisted;
                EndVisted=temp;
                forward=!forward;
            }
            for (String CurrentWord :BeginVisted) {
                char[] charArray = CurrentWord.toCharArray();
                for (int j = 0; j < WordLength; j++) {
                    char originalChar = charArray[j];
                    for (char k = 'a'; k <= 'z'; k++) {
                        charArray[j] = k;
//                        和原来一样的单词不可以计算
                        if (charArray[j] == originalChar) {
                            continue;
                        }
                        String nextWord = new String(charArray);
                        if (wordSet.contains(nextWord)) {
                            if(EndVisted.contains(nextWord)){
//                                这里就是连通了,那么visited那边,一定有了,因为每一层遍历结束过后,才会加入visited
                                found=true;
                                addTographic(Make_Graphic,forward,CurrentWord,nextWord);
                            }
                            if (!visited.contains(nextWord)) {
                                nextLevelVisited.add(nextWord);
                                addTographic(Make_Graphic,forward,CurrentWord,nextWord);
                            }
                        }
                    }
                    charArray[j] = originalChar;
                }
            }
            if (found) {
                break;
            }
            BeginVisted=nextLevelVisited;
            visited.addAll(nextLevelVisited);
        }
        return found;
    }

    public void dfs(String BeginWord, String EndWord, Map<String, Set<String>> graphic, Stack<String> path, List<List<String>> res) {
        if (BeginWord.equals(EndWord)) {
            res.add(new ArrayList<>(path));
        }
        if (!graphic.containsKey(BeginWord)) {
            return;
        }
        Set<String> NextWord = graphic.get(BeginWord);
        for (String next : NextWord) {
            path.push(next);
            dfs(next, EndWord, graphic, path, res);
            path.pop();
        }
    }
    public void addTographic(Map<String,Set<String>> graphic,boolean forward,String currentWord,String nextWord){
        if(!forward){
//            是反过来的,就要反着添加
            String temp=currentWord;
            currentWord=nextWord;
            nextWord=temp;
        }
        graphic.computeIfAbsent(currentWord,a->new HashSet<>());
        graphic.get(currentWord).add(nextWord);

    }
}

总结
  • 死磕真的把一个题搞出来了,看了别人的解答n遍
  • 保持刷题·,不然手感好难找回 /(ㄒoㄒ)/~~
  • 坚持呀! 冲冲冲~~~ (ง •_•)ง
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值