BFS and Bidirectional Search

leetcode题目链接:
752.open the Lock
https://leetcode.com/problems/open-the-lock/description/

遇到一个很有意思的算法,Bidirectional Search.通常我们做bfs都是从原点到目的地单向的遍历,而Bidirectional Search从原点和目的地双向遍历,直到遍历的节点相交,因此效率有较大提升。

1.My ordinary BFS code:

class Solution {
    public int openLock(String[] deadends, String target) {
        int[][] dirs = {{0, 1}, {0, -1}, {1, 1}, {1, -1}, {2, 1}, {2, -1}, {3, 1}, {3, -1}};
        Queue<String> queue = new LinkedList<>();
        Set<String> visited = new HashSet<>();

        for(String end : deadends)  visited.add(end);
        if(visited.contains("0000"))  return -1;

        queue.add("0000");
        visited.add("0000");
        int minmoves = 0;
        while(!queue.isEmpty()){
            int size = queue.size();
            while(size > 0){
                String start = queue.poll();
                if(start.equals(target)) return minmoves;
                for(int[] dir : dirs){
                    String after = transform(start, dir);
                    if(!visited.contains(after)){
                        queue.offer(after);
                        visited.add(after);
                    }
                }
                size--;
            }
            minmoves++;
        }

        return -1;
    }
    public String transform(String str, int[] dir){
        char[] cArr = str.toCharArray();

        if(cArr[dir[0]] == '0' && dir[1] == -1){
            cArr[dir[0]] = '9';
        }else if(cArr[dir[0]] == '9' && dir[1] == 1){
            cArr[dir[0]] = '0';
        }else if(dir[1] == 1){
            cArr[dir[0]]++;
        }else{
            cArr[dir[0]]--;
        }

        return new String(cArr);
    }
}

2-end BFS:

class Solution {
    public int openLock(String[] deadends, String target) {
        Set<String> begin = new HashSet<>();
        Set<String> end = new HashSet<>();
        Set<String> deads = new HashSet<>(Arrays.asList(deadends));
        begin.add("0000");
        end.add(target);
        int level = 0;
        while(!begin.isEmpty() && !end.isEmpty()) {
            Set<String> temp = new HashSet<>();
            for(String s : begin) {
                if(end.contains(s)) return level;
                if(deads.contains(s)) continue;
                deads.add(s);
                StringBuilder sb = new StringBuilder(s);
                for(int i = 0; i < 4; i ++) {
                    char c = sb.charAt(i);
                    String s1 = sb.substring(0, i) + (c == '9' ? 0 : c - '0' + 1) + sb.substring(i + 1);
                    String s2 = sb.substring(0, i) + (c == '0' ? 9 : c - '0' - 1) + sb.substring(i + 1);
                    if(!deads.contains(s1))
                        temp.add(s1);
                    if(!deads.contains(s2))
                        temp.add(s2);
                }
            }
            level ++;
            begin = end;
            end = temp;
        }

        return -1;
    }
}

optimized 2-end BFS:

class Solution {
    public int openLock(String[] deadends, String target) {
        Set<String> begin = new HashSet<>();
        Set<String> end = new HashSet<>();
        Set<String> deads = new HashSet<>(Arrays.asList(deadends));

        begin.add("0000");
        end.add(target);
        int level = 0;
        Set<String> temp;
        while(!begin.isEmpty() && !end.isEmpty()) {
            //优化的地方在这里,总是从较少元素的那一端开始遍历
            if (begin.size() > end.size()) {
                temp = begin;
                begin = end;
                end = temp;
            }
            temp = new HashSet<>();
            for(String s : begin) {
                if(end.contains(s)) return level;
                if(deads.contains(s)) continue;
                deads.add(s);
                StringBuilder sb = new StringBuilder(s);
                for(int i = 0; i < 4; i ++) {
                    char c = sb.charAt(i);
                    String s1 = sb.substring(0, i) + (c == '9' ? 0 : c - '0' + 1) + sb.substring(i + 1);
                    String s2 = sb.substring(0, i) + (c == '0' ? 9 : c - '0' - 1) + sb.substring(i + 1);
                    if(!deads.contains(s1)) temp.add(s1);
                    if(!deads.contains(s2)) temp.add(s2);
                }
            }
            level++;
            begin = temp;
        }

        return -1;
    }
}

如果对BFS和Bidirectional Search感兴趣的话,以下两个链接可供你参考:
1.一个leetcode上面关于BFS和2-end BFS的总结:
https://leetcode.com/problems/open-the-lock/discuss/110237/Regular-java-BFS-solution-and-2-end-BFS-solution-with-improvement

2.geekbygeek上面关于Bidirectional Search的算法和描述:
https://www.geeksforgeeks.org/bidirectional-search/

    原文作者:BFS
    原文地址: https://blog.csdn.net/LaputaFallen/article/details/79456432
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞