LeetCode 317. Shortest Distance from All Buildings(最短建筑距离)

17 篇文章 0 订阅
12 篇文章 0 订阅

原题网址:https://leetcode.com/problems/shortest-distance-from-all-buildings/

You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 01 or 2, where:

  • Each 0 marks an empty land which you can pass by freely.
  • Each 1 marks a building which you cannot pass through.
  • Each 2 marks an obstacle which you cannot pass through.

For example, given three buildings at (0,0)(0,4)(2,2), and an obstacle at (0,2):

1 - 0 - 2 - 0 - 1
|   |   |   |   |
0 - 0 - 0 - 0 - 0
|   |   |   |   |
0 - 0 - 1 - 0 - 0

The point (1,2) is an ideal empty land to build a house, as the total travel distance of 3+3+1=7 is minimal. So return 7.

Note:
There will be at least one building. If it is not possible to build such house according to the above rules, return -1.

方法:从每一栋建筑出发,广度优先搜索,更新该建筑到各块空地的距离。另外一个诀窍就是如果有两栋建筑之间不连通,则直接返回-1。

public class Solution {
    private int[] r = {-1, 1, 0, 0};
    private int[] c = {0, 0, -1, 1};
    
    private boolean update(int[][] grid, int buildings, int row, int col, int[][] reach, int[][] distance) {
        boolean[][] visited = new boolean[grid.length][grid[0].length];
        Position position = new Position(row, col, 0);
        Position tail = position;
        visited[row][col] = true;
        int reached = 1;
        while (position != null) {
            distance[position.row][position.col] += position.distance;
            for(int i=0; i<4; i++) {
                int y = position.row + r[i];
                int x = position.col + c[i];
                if (y >= 0 && y < grid.length && x >= 0 && x < grid[y].length && !visited[y][x]) {
                    visited[y][x] = true;
                    if (grid[y][x] == 1) {
                        reached ++;
                    } else if (grid[y][x] == 0) {
                        reach[y][x] ++;
                        tail.next = new Position(y, x, position.distance + 1);
                        tail = tail.next;
                    }
                }
            }
            position = position.next;
        }
        // System.out.printf("row=%d, col=%d, reached=%d, buildings=%d\n", row, col, reached, buildings);
        return reached == buildings;
    }
    
    public int shortestDistance(int[][] grid) {
        int[][] distance = new int[grid.length][grid[0].length];
        int[][] reach = new int[grid.length][grid[0].length];
        int buildings = 0;
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j] == 1) buildings ++;
            }
        }
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j] == 1) {
                    if (!update(grid, buildings, i, j, reach, distance)) return -1;
                }
            }
        }
        // System.out.println();
        // for(int i=0; i<grid.length; i++) {
        //     for(int j=0; j<grid[i].length; j++) System.out.print(distance[i][j]+",");
        //     System.out.println();
        // }
        int min = -1;
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j] == 0 && reach[i][j] == buildings && (min == -1 || distance[i][j] < min)) min = distance[i][j];
            }
        }
        return min;
    }
}
class Position {
    int row, col;
    int distance;
    Position next;
    Position(int row, int col, int distance) {
        this.row = row;
        this.col = col;
        this.distance = distance;
    }
}

另一种实现:

public class Solution {
    private int[] ro = {-1, 1, 0, 0};
    private int[] co = {0, 0, -1, 1};
    private int br, bc;
    private int go(int[][] grid, boolean[][] visit, int row, int col) {
        int count = 0;
        if (visit[row][col] || grid[row][col] == 2) return 0;
        if (grid[row][col] == 1) {
            visit[row][col] = true;
            return 1;
        }
        visit[row][col] = true;
        for(int i=0; i<4; i++) {
            int r = row + ro[i];
            int c = col + co[i];
            if (r>=0 && r<grid.length && c>=0 && c<grid[r].length) count += go(grid, visit, r, c);
        }
        return count;
    }
    private int buildings(int[][] grid) {
        int count = 0;
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j] == 1) {
                    br = i;
                    bc = j;
                    count ++;
                }
            }
        }
        return count;
    }
    private void calc(int[][] grid, int[][] total, int[][] reach, int row, int col) {
        int[][] dist = new int[grid.length][grid[0].length];
        LinkedList<Step> queue = new LinkedList<>();
        queue.add(new Step(row, col, 0));
        while (!queue.isEmpty()) {
            Step step = queue.remove();
            for(int i=0; i<4; i++) {
                int r = step.row+ro[i];
                int c = step.col+co[i];
                if (r>=0 && r<grid.length && c>=0 && c<grid[r].length && dist[r][c]==0 && grid[r][c]==0) {
                    dist[r][c] = step.step+1;
                    total[r][c] += dist[r][c];
                    reach[r][c] ++;
                    queue.add(new Step(r, c, step.step+1));
                }
            }
        }
    }
    public int shortestDistance(int[][] grid) {
        int buildings = buildings(grid);
        int go = 0;
        boolean[][] visit = new boolean[grid.length][grid[0].length];
        for(int i=0; i<4; i++) {
            int r = br+ro[i];
            int c = bc+co[i];
            if (r>=0 && r<grid.length && c>=0 && c<grid[r].length && grid[r][c]==0) {
                go += go(grid, visit, r, c);
            }
        }
        if (buildings != go) return -1;
        int[][] total = new int[grid.length][grid[0].length];
        int[][] reach = new int[grid.length][grid[0].length];
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j]==1) {
                    calc(grid, total, reach, i, j);
                }
            }
        }
        int min = Integer.MAX_VALUE;
        for(int i=0; i<grid.length; i++) {
            for(int j=0; j<grid[i].length; j++) {
                if (grid[i][j]==0 && reach[i][j]==buildings) min = Math.min(min, total[i][j]);
            }
        }
        return min;
    }
}
class Step {
    int row, col, step;
    Step(int row, int col, int step) {
        this.row = row;
        this.col = col;
        this.step = step;
    }
}

另一种实现:

public class Solution {
    private int[] dy = {0, 0, -1, 1};
    private int[] dx = {-1, 1, 0, 0};
    private void find(int[][] grid, int[][] reach, int[][] total, int y, int x) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dist = new int[m][n];
        ArrayDeque<Position> deque = new ArrayDeque<>();
        deque.add(new Position(y, x, 0));
        while (!deque.isEmpty()) {
            Position pos = deque.remove();
            for(int i = 0; i < 4; i++) {
                int ny = pos.y + dy[i];
                int nx = pos.x + dx[i];
                if (ny < 0 || ny >= m || nx < 0 || nx >= n) continue;
                if (grid[ny][nx] != 0) continue;
                if (dist[ny][nx] != 0) continue;
                Position next = new Position(ny, nx, pos.d + 1);
                reach[next.y][next.x]++;
                dist[next.y][next.x] = next.d;
                total[next.y][next.x] += next.d;
                deque.add(next);
            }
        }
    }
    public int shortestDistance(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) return -1;
        int m = grid.length;
        int n = grid[0].length;
        int b = 0;
        for(int i = 0; i < m; i ++) {
            for(int j = 0; j < n; j++) {
                if (grid[i][j] == 1) b++;
            }
        }
        int[][] reach = new int[m][n];
        int[][] total = new int[m][n];
        for(int i = 0; i < m; i ++) {
            for(int j = 0; j < n; j++) {
                if (grid[i][j] != 1) continue;
                find(grid, reach, total, i, j);
            }
        }
        int min = -1;
        for(int i = 0; i < m; i ++) {
            for(int j = 0; j < n; j++) {
                if (grid[i][j] == 0 && reach[i][j] == b && (min == -1 || total[i][j] < min)) {
                    min = total[i][j];
                }
            }
        }
        return min;
    }
}
class Position {
    int y, x;
    int d;
    Position(int y, int x, int d) {
        this.y = y;
        this.x = x;
        this.d = d;
    }
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值