Jerry's Blog

Recording what I learned everyday

View on GitHub


19 September 2019

LeetCode(12) -- 463, 475

by Jerry Zhang

P463. Island Perimeter (Easy)

用一个二维数组代表一张地图,1代表陆地,0代表水域。只有一个岛,求它的周长。

我的思路

遍历整个数组,如果是1,就检查它的四个方向,如果是0,周长就加1。

从第一行开始,首先找到第一个1。然后以这个1为起点,用DFS算法遍历所有连通的陆地部分.

讨论区

public class Solution {
    public int islandPerimeter(int[][] grid) {
        if (grid == null) return 0;
        for (int i = 0 ; i < grid.length ; i++){
            for (int j = 0 ; j < grid[0].length ; j++){
                if (grid[i][j] == 1) {
                    return getPerimeter(grid,i,j);
                }
            }
        }
        return 0;
    }

    public int getPerimeter(int[][] grid, int i, int j){
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) {return 1;}
        if (grid[i][j] == 0) {
            return 1;
        }
        if (grid[i][j] == -1) return 0;

        int count = 0;
        grid[i][j] = -1;

        count += getPerimeter(grid, i-1, j);
        count += getPerimeter(grid, i, j-1);
        count += getPerimeter(grid, i, j+1);
        count += getPerimeter(grid, i+1, j);

        return count;

    }
}

34%

最优解

class Solution {
    public int islandPerimeter(int[][] grid) {
        int ans = 0, R = grid.length, C = R == 0 ? 0 : grid[0].length;
        for(int r = 0; r < R; ++r){
            for(int c = 0; c < C; ++c){
                ans += grid[r][c] *
                    (4 - (r < 1 ? 0 : 2*grid[r-1][c]) - (c < 1 ? 0 : 2*grid[r][c-1]));
            }
        }
        return ans;
    }
}

遍历整个数组。这个解法中,判断周长增量的方法非常有意思。首先,从一个“口”变成一个“日”,它的周长增加了多少?由4变成了6。为什么呢?我们可以把它理解为,左右两条边向下条延长了1个长度,因此周长的增量就是2。同理,如果在已有的方格右边新加一个方格,那增量也是2。如果它左边和上边都已经有了,那增量其实就是0。

(4 - (r < 1 ? 0 : 2*grid[r-1][c]) - (c < 1 ? 0 : 2*grid[r][c-1]));这行代码表达的就是这个意思。

P475. Heaters (Easy)

给房子供暖。第一个数组代表房子的位置,第二个数组代表暖气的位置。求暖气的最小半径。

Input: [1,2,3],[2]
Output: 1
Explanation: The only heater was placed in the position 2, and if we use the radius 1 standard, then all the houses can be warmed.
Input: [1,2,3,4],[1,4]
Output: 1
Explanation: The two heater was placed in the position 1 and 4. We need to use radius 1 standard, then all the houses can be warmed.

我的思路

我的代码

public class E_475_Heaters {
    public int findRadius(int[] houses, int[] heaters) {
        Arrays.sort(houses);
        Arrays.sort(heaters);
        int r = heaters[0] - houses[0];
        int close;
        for (int i = 1, j = 0; i < houses.length && j < heaters.length - 1; i++) {
            if (houses[i] >= heaters[j] && houses[i] <= heaters[j+1]) {
                close = Math.min(houses[i] - heaters[j], heaters[j+1] - houses[i]);
                r = Math.max(close, r);
            } else {
                j++;
            }
        }
        r = Math.max(r, houses[houses.length - 1] - heaters[heaters.length - 1]);
        return r;
    }

    public static void main(String[] args) {
        int[] houses = {101027544,144108930,282475249,457850878,458777923,470211272,622650073,984943658};
        int[] heat =   {114807987,115438165,137522503,143542612,16531729,441282327,74243042,784484492,823378840,
                823564440};
        int radius = new E_475_Heaters().findRadius(houses, heat);
        System.out.println("radius = " + radius);
    }
}

代码是错误的,一直有bug,放弃了

讨论区

public class Solution {
    public int findRadius(int[] houses, int[] heaters) {
        Arrays.sort(houses);
        Arrays.sort(heaters);

        // pre represents the heater that's ahead of the current house
        int pre = heaters[0];
        // index of the heater
        int i = 0;
        int res = 0;
        for (int house : houses) {
            // looking for the heater that's immediately after the current house
            while (i < heaters.length - 1 && heaters[i] < house) {
                pre = heaters[i];
                i++;
            }

            int distanceToPreHeater = Math.abs(house - pre);
            int distanceToAfterHeater = Math.abs(house - heaters[i]);
            res = Math.max(res, Math.min(distanceToPreHeater, distanceToAfterHeater));
        }

        return res;
    }
}

其实我的代码已经很接近了。这个题肯定是要两个数组同时推进的过程中比大小。外层循环肯定是长的数组,也就是houses。第一个任务就是找到离我当前房子位置最近的前一个暖气。只要我的暖气不是最后一个,并且暖气的位置在当前房子位置的左边,就再试下一个暖气,直到找到最接近房子位置的暖气为止。

第二个任务是计算两个绝对值——到左边这个暖气的距离和到右边暖气的距离。这两个距离中较小的一个,就决定了当前点位需要的暖气最小供暖距离。所有点位供暖距离的最大值,就是结果。

最优解

public class Solution {
    public int findRadius(int[] houses, int[] heaters) {
        Arrays.sort(houses);
        Arrays.sort(heaters);

        int index = 0;
        int radius = 0;
        int left = -heaters[index];
        int right = heaters[index];

        for (int house : houses) {
            while (house > right) {
                left = right;
                right = index < heaters.length - 1? heaters[++index] : Integer.MAX_VALUE;
            }

            while (left < house - radius && house + radius < right) {
                if (left < 0) {
                    radius = Math.abs(house - right);
                } else if (right ==Integer.MAX_VALUE ) {
                    radius = Math.abs(house - left);
                } else if (Math.abs(house - right) <  Math.abs(house - left) )  {
                    radius =  Math.abs(house - right);
                } else {
                    radius = Math.abs(house - left);
                }
            }
        }
        return radius;
    }
}
tags: LeetCode