[leetCode]1036. 逃离大迷宫

在这里插入图片描述

广度优先搜索

class Solution {
    // 定义一个方向数组
    static int[][] directions = new int[][]{{0, 1}, {1, 0}, {-1, 0},{0, -1}};
    // X,Y的上限
    static int limit = (int)1e6;
    public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
        if (blocked.length == 0) return true;
        // 使用一个哈希表,保存被封锁的网格
        Set<String> blocks = new HashSet<>();
        for (int[] block : blocked) {
            blocks.add(block[0] + ":" + block[1]);
        }
        /* 因为只迭代20000步, 如果是目标点在被封锁的区域内正着跑也可以到
        20000步但是到不了目标点, 正反都跑一次才保证能到达目标点*/
        // 目标的有可能被全部包围
        return bfs(source, target, blocks) && bfs(target, source, blocks);
    }

    public boolean bfs(int[] source, int[] target, Set<String> blocks) {
        // 使用一个哈希表保存已经走过的节点
        Set<String> seen = new HashSet<>();
        seen.add(source[0] + ":" + source[1]);
        // 使用一个队列保存当前能走的网格坐标
        Queue<int[]> queue = new LinkedList<>();
        queue.add(source);
        while (!queue.isEmpty()) {
            // 当前坐标
            int[] cur = queue.poll();
            // 遍历方向数组directions
            for (int[] dir : directions) {
                // (nextX, nextY)为下一个网格点坐标
                int nextX = dir[0] + cur[0];
                int nextY = dir[1] + cur[1];
                // 如果坐标越界跳过这个方向
                if (nextX < 0 || nextY < 0 || nextX > limit || nextY > limit) continue;
                // 用于哈希表查询,如果该坐标已经走过或者被封锁则走下一个方向
                String key = nextX + ":" + nextY;
                if (seen.contains(key) || blocks.contains(key)) continue;
                // 走到了目标点返回true
                if (nextX == target[0] && nextY == target[1]) return true;
                queue.offer(new int[]{nextX, nextY});
                // 添加到已走过的点中
                seen.add(key);
            }
            // 因为 blocked 的 length 是 200
            // 如果使用这 200 个 block 可以围成最大的区域是 19900,如下:
            /*
                0th      _________________________
                        |O O O O O O O X
                        |O O O O O O X
                        |O O O O O X
                        |O O O O X
                        .O O O X
                        .O O X
                        .O X
                200th   |X
            从上面可以计算出 block(即 X)可以围城的最大区域(是一个角的三角形),大小计算如下:
            1 + 2 + 3 + 4 + ... + 199 = (1 + 199) * 199 / 2 = 19900
            这里我们向上取整为 20000。
            */
            // 也就是说,如果迭代了 20000 步还能继续走的话,那么是肯定可以到达 target 的
            if (seen.size() > 19900) return true;
        }
        return false;
    }
    
}
posted @ 2020-10-15 10:54  消灭猕猴桃  阅读(106)  评论(0编辑  收藏  举报