单词接龙 II——Dijkstra算法与BFS

2021-09-04  本文已影响0人  抬头挺胸才算活着

参考资料:
https://leetcode-cn.com/problems/word-ladder-ii/
https://www.jianshu.com/p/2061194d355e

通过阅读题意,我们知道这个题目就是图的最短路径,只不过要记录下整个路径过程。图的最短路径有Dijkstra算法和BFS,只不过BFS在遍历的时候要注意防止重复。Dijkstra算是就是一种BFS,只不过BFS每次是遍历一层,Dijkstra算法每次是遍历最近的一个。

我们这里采用BFS更加清晰一点,这里的关键在于如何防止重复。
每个路径想要不重复走入重复,最直观的想法是给每个路径添加一个set集合,保存之前走过的路径,这样的成本太高,可能会造成超时。
这里我们可以采用Dijkstra的costs数组,这个数组保存了目前为止从起点到各个终点之间的最短路径,如果同一条路径之前到过A点,下次自然不会再进入A点,这个效果跟上面的方法是一样的。但是更妙的来了,其他路径如果到A点的路径长度大于之前路径到A点的路径长度也不会进入A,也就是只有一条路径会经过A,让这条路径经过A去探索到达终点的路径,避免了更多重复,除非有找到更近的A。还有更妙的,我们不怕到终点有冗余的路径,因为我们前面说了cost能保证到其他点的路径都是最短的,所以下面我们一个个遍历也是可以的,请看第二段代码。
这样我们的代码就跟Dijkstra算法一样了,除了Dijkstra算法每次需要找加入最短路径对应的节点,而我们因为节点之间的路径都是1,所以最短的都是排在前面的,所以不用这样的额外操作。

    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        List<List<String>> results = new LinkedList<>();
        LinkedList<LinkedList<String>> lastVisitedLadder = new LinkedList<>();

        Set<String> wordSet = wordList.stream().collect(Collectors.toSet());

        if (!wordSet.contains(endWord)) {
            return results;
        }

        LinkedList<String> beginLadder = new LinkedList<>();
        beginLadder.add(beginWord);
        lastVisitedLadder.add(beginLadder);

        // costs 是画龙点睛之笔,costs 是为了减少在图的遍历过程中的重复遍历,就像Dijsktra中的costs数组一样
        Map<String, Integer> costs = wordList.stream().collect(Collectors.toMap(x -> x, x -> Integer.MAX_VALUE));
        costs.put(beginWord, 0);

        while (!lastVisitedLadder.isEmpty()) {
            boolean foundEndWord = false;
            int size = lastVisitedLadder.size();
            for (int i = 0; i < size; i++) {
                LinkedList<String> visitedLadder = lastVisitedLadder.remove();
                String lastWord = visitedLadder.getLast();

                for (String word : wordSet) {
                    int cost = costs.get(lastWord) + 1;
                    if (cost <= costs.get(word) && isNext(lastWord, word)) {
                        costs.put(word, cost);

                        if(word.equals(endWord)) {
                            foundEndWord = true;
                            LinkedList<String> newLadder = new LinkedList<>(visitedLadder);
                            newLadder.add(word);
                            results.add(newLadder);
                        }

                        LinkedList<String> newLadder = new LinkedList<>(visitedLadder);
                        newLadder.add(word);
                        lastVisitedLadder.add(newLadder);
                    }
                }
            }
            System.out.println(lastVisitedLadder.size());

            if (foundEndWord) {
                break;
            }
        }

        return results;
    }

去掉BFS的每层forsize循环

    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        List<List<String>> results = new LinkedList<>();
        LinkedList<LinkedList<String>> lastVisitedLadder = new LinkedList<>();

        Set<String> wordSet = wordList.stream().collect(Collectors.toSet());

        if (!wordSet.contains(endWord)) {
            return results;
        }

        LinkedList<String> beginLadder = new LinkedList<>();
        beginLadder.add(beginWord);
        lastVisitedLadder.add(beginLadder);

        // costs 是画龙点睛之笔,costs 是为了减少在图的遍历过程中的重复遍历,就像Dijsktra中的costs数组一样
        Map<String, Integer> costs = wordList.stream().collect(Collectors.toMap(x -> x, x -> Integer.MAX_VALUE));
        costs.put(beginWord, 0);

        while (!lastVisitedLadder.isEmpty()) {
            boolean foundEndWord = false;
            LinkedList<String> visitedLadder = lastVisitedLadder.remove();
            String lastWord = visitedLadder.getLast();

            for (String word : wordSet) {
                int cost = costs.get(lastWord) + 1;
                if (cost <= costs.get(word) && isNext(lastWord, word)) {
                    costs.put(word, cost);

                    if(word.equals(endWord)) {
                        foundEndWord = true;
                        LinkedList<String> newLadder = new LinkedList<>(visitedLadder);
                        newLadder.add(word);
                        results.add(newLadder);
                    }

                    LinkedList<String> newLadder = new LinkedList<>(visitedLadder);
                    newLadder.add(word);
                    lastVisitedLadder.add(newLadder);
                }
            }
        }

        return results;
    }
上一篇下一篇

猜你喜欢

热点阅读