JAVA程序设计:逃离大迷宫(LeetCode:1036)

在一个 10^6 x 10^6 的网格中,每个网格块的坐标为 (x, y),其中 0 <= x, y < 10^6。

我们从源方格 source 开始出发,意图赶往目标方格 target。每次移动,我们都可以走到网格中在四个方向上相邻的方格,只要该方格不在给出的封锁列表 blocked 上。

只有在可以通过一系列的移动到达目标方格时才返回 true。否则,返回 false。

 

示例 1:

输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
输出:false
解释:
从源方格无法到达目标方格,因为我们无法在网格中移动。
示例 2:

输入:blocked = [], source = [0,0], target = [999999,999999]
输出:true
解释:
因为没有方格被封锁,所以一定可以到达目标方格。
 

提示:

0 <= blocked.length <= 200
blocked[i].length == 2
0 <= blocked[i][j] < 10^6
source.length == target.length == 2
0 <= source[i][j], target[i][j] < 10^6
source != target

思路:由于方格图的面积很大,如果我们一味的走向答案则必定会超时,而我们观察到blocked数组只有200的大小,因此它所能包住的区域是有限的,因此我们可以仍然采用一般的BFS方法,只是我们需要让其能够提前退出,而经分析我们可以知道当移动次数超过20000次左右就能证明其一定能够通过一条路径到达target(换句话说,就是包不住),而虽然起点包不住,但是终点有可能包住的,因此我们需要把终点看做起点再来一遍。

class Solution {

    private int num;
    private boolean flag;
    private int[] dx = new int[]{0, 0, 1, -1};
    private int[] dy = new int[]{1, -1, 0, 0};
    private Map<String, Boolean> map;
    private Map<String, Boolean> vised;

    public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {

        map = new HashMap<>();

        int len = blocked.length;
        for (int i = 0; i < len; i++) {
            String s = String.valueOf(blocked[i][0]) + "#" + String.valueOf(blocked[i][1]);
            map.put(s, true);
        }

        return jud(blocked, source, target) && jud(blocked, target, source);

    }

    private boolean jud(int[][] blocked, int[] source, int[] target) {

        num = 0;
        flag = false;
        vised = new HashMap<>();

        bfs(source[0], source[1], target[0], target[1]);

        return flag;

    }

    private void bfs(int x, int y, int target_x, int target_y) {

        Queue<int[]> q = new LinkedList<>();

        num = 1;
        q.add(new int[]{x, y});
        String s = String.valueOf(x) + "#" + String.valueOf(y);
        vised.put(s, true);

        while (!q.isEmpty()) {
            int[] now = q.poll();
            if (now[0] == target_x && now[1] == target_y) {
                flag = true;
                return;
            }
            for (int i = 0; i < 4; i++) {
                int xx = now[0] + dx[i];
                int yy = now[1] + dy[i];
                String ss = String.valueOf(xx) + "#" + String.valueOf(yy);

                if (xx < 0 || yy < 0 || check(xx, yy) || vised.containsKey(ss))
                    continue;
                num++;
                if (num >= 20000) {
                    flag = true;
                    return;
                }
                q.add(new int[]{xx, yy});
                vised.put(ss, true);
            }
        }
    }

    private boolean check(int x, int y) {
        String s = String.valueOf(x) + "#" + String.valueOf(y);
        return map.containsKey(s);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值