LeetCode #475 Heaters

题目

Winter is coming! Your first job during the contest is to design a standard heater with fixed warm radius to warm all the houses.
Now, you are given positions of houses and heaters on a horizontal line, find out minimum radius of heaters so that all houses could be covered by those heaters.
So, your input will be the positions of houses and heaters seperately, and your expected output will be the minimum radius standard of heaters.

note:

  1. Numbers of houses and heaters you are given are non-negative and will not exceed 25000.
  2. Positions of houses and heaters you are given are non-negative and will not exceed 109 .
  3. As long as a house is in the heaters’ warm radius range, it can be warmed.
  4. All the heaters follow your radius standard and the warm radius will the same.

Example 1:

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.

Example 2:

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.

解题思路

刚开始没有想排序的问题,因为觉得在 O(n) 的复杂度下可以完成这道题。基本思路是遍历所有的 heaters ,找到它们两两之间最大的间距(当然包括一些 corner cases 的判断,如一些heaters所在的位置在整个houses数组之外,但总体思路就是求最大的间距)然后除以2,得到最小的radius。后来掉入了无数的大坑后终于意识到自己是一个傻逼,具体掉的坑如下:

1. [1,2,3,5,15], [2,30] 最小的radius是 15 - 2 = 13,但是最大间距是 (30 - 2) / 2 = 14,显然不是答案,原因就在于 最大间距 / 2 所得的radius最大范围处不一定有house。像这个例子,如果 radius == 14 的话,则 2 + 14 = 16,但是在16这个位置上根本就没有house,所以根本不需要这么大的radius。
2. [1,5] [10] 所有heaters均在houses的位置外面时,比较也会出错。

意识到自己的傻逼错误并请教过大神后,终于决定痛改前非,采用 O(nlogn) 的算法完成这道题目,具体思路如下:

  1. 先将 heaters 数组进行排序,然后对于每一个house,在已排序的 heaters 数组中利用二分搜索找到这个house的位置,如果找到了,则返回相应的下标,如果没有找到,则以负数的形式返回这个 house 在 heaters 数组的插入位置(也就是 heaters 数组中第一个大于这个 house 的元素的下标)。
  2. 对于每个 house,比较与其相邻的两个heaters哪个距离这个 house 更近,如果这个更近的距离比原来已经找到的最小的 radius 大,则更新这个最小的 radius。
  3. 对一些 corner cases进行特殊的处理,如搜索到的 house 的插入位置位于已排序的 heaters 数组之外等。
  4. 二分搜索算法直接使用 Java 提供的 Arrays.binarySearch() 方法,这个方法当没有搜索到目标元素时,将会以负数形式返回该目标元素在数组中的插入位置,这个负数形式为 -(insert location) - 1

Java 实现代码

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

        for (int house : houses) {
            int index = Arrays.binarySearch(heaters, house);
            int tmpRadius = 0;

            if (index < 0) {
                index = -(index + 1);

                if (index == 0) {
                    tmpRadius = heaters[0] - house;
                } else if (index >= heaters.length) {
                    tmpRadius = house - heaters[heaters.length - 1];
                } else {
                    tmpRadius = Math.min(heaters[index] - house, house - heaters[index - 1]);
                }
            }

            if (tmpRadius > minRadius) { minRadius = tmpRadius; }
        }

        return minRadius;
    }
}

在这里我想解释一下Java的 Arrays.binarySearch() 为什么要返回 -(insert location) - 1 而不是 -insert location 。这是为了使得当所要查找的元素不在给定的数组中时,函数统一返回负数。因为如果在查找的元素比给定数组中的所有元素都要小,则该元素在数组中的插入位置是 00 的相反数就是它自己,如果返回 -insert location 的话将会返回 0 ,此时就要对返回 0 的情况分开讨论了:有可能该元素在数组中被找到了,下标是 0;但也有可能没找到,插入位置是 0 。而通过返回 -(insert location) - 1,只要没找到,返回的就肯定是负数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值