【LeetCode】475. Heaters (java實現)

原題連接

https://leetcode.com/problems/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:code

Numbers of houses and heaters you are given are non-negative and will not exceed 25000.
Positions of houses and heaters you are given are non-negative and will not exceed 10^9.
As long as a house is in the heaters' warm radius range, it can be warmed.
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:leetcode

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.

題目要求

冬天到了,須要利用加熱器爲房屋取暖。多個房屋和多個取暖器都在一條直線上,每一個取暖器只能加熱一段範圍內的房屋。給定兩個數組,分別表示房屋的座標和取暖器的座標,若是要求每一個房屋都可以被加熱,求出取暖器最小的加熱範圍半徑。好比房屋座標爲[1,2,3],取暖器座標爲[2],那麼取暖器的加熱範圍半徑爲1就能夠爲全部房屋取暖了。get

解法

解法一:超時的作法。將全部的取暖器放入一個map中,而後對每一個house,嘗試在其座標+j和-j(從1開始遞增)的位置尋找取暖器(在map中搜索),若是找到,那麼這個j就是這個house的最小半徑。最後,對每一個house的最小半徑再求最小值。這種作法雖然簡單容易理解,可是性能並不高,尤爲在數字較大時,很容易超時,由於每一個house都是遞增+j-j的搜索取暖器。input

public int findRadius(int[] houses, int[] heaters) {
    Arrays.sort(houses);
    Arrays.sort(heaters);
    
    int posMin = houses[0] > heaters[0] ? heaters[0] : houses[0];
    int posMax = houses[houses.length - 1] > heaters[heaters.length - 1] ? houses[houses.length - 1] : heaters[heaters.length - 1];
    
    HashMap<Integer, Boolean> heaterMap = new HashMap<Integer, Boolean>();
    // add to HashMap, to increase search speed.
    for (int i = 0; i < heaters.length; i++) {
        heaterMap.put(heaters[i], true);
    }
    
    int max = 0;
    for (int i = 0; i < houses.length; i++) {
        int pos = houses[i];
        for (int j = 0; pos - j >= posMin || pos + j <= posMax; j++) {
            // try to search left or right, onece found, judge max and break;
            if (heaterMap.containsKey(pos - j)) {
                max = (max < j? j : max);
                break;
            }
            if (heaterMap.containsKey(pos + j)) {
                max = (max < j? j : max);
                break;
            }
        }
    }
    
    return max;
}

解法二:在方法1的基礎上作了優化。既然是對每一個house都+j-j的搜索,其實就是嘗試在每一個house的左邊和右邊找到最近的取暖器,而後在左邊和右邊的取暖器中找出個最小半徑。最後再在全部house的最小半徑中,找出一個最大值,就能夠保證全部house都能取暖了。所以,這種解法,就是建立兩個新數組,表示每一個house的左邊和右邊取暖器的座標,這裏有一個優化(我認爲是一個優化,不過也能夠不用這種方式),就是座標數組裏保存的都是真實座標+1,這樣,0就能夠表示house的左邊或者右邊沒有取暖器了。it

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

    int left = 0, right = heaters.length - 1;
    int[] lefts = new int[houses.length];
    int[] rights = new int[houses.length];
    for (int i = 0; i < houses.length; i++) {
        while (left < heaters.length && heaters[left] <= houses[i]) {
            lefts[i] = left + 1;
            left++;
        }
        left = lefts[i] != 0 ? (lefts[i] - 1) : 0;
        while (right >= left && heaters[right] >= houses[i]) {
            rights[i] = right + 1;
            right--;
        }
        right = heaters.length - 1;
    }
    
    int ret = 0;
    for (int i = 0; i < houses.length; i++) {
        int min = Integer.MAX_VALUE;
        if (lefts[i] != 0) {
            min = Math.min(houses[i] - heaters[lefts[i] - 1], min);
        }
        if (rights[i] != 0) {
            min = Math.min(heaters[rights[i] - 1] - houses[i], min);
        }
        ret = Math.max(min, ret);
    }

    System.out.println(ret);
    return ret;
}

Top解法:這是Discuss中的top解法。先將取暖器數組排序,在遍歷全部house,對每一個house,在取暖器數組中進行binary search,若是命中,則說明取暖器位置和house位置重合,這個house的最小半徑爲0;若是沒有命中,則使用返回的index,將index左邊和右邊的取暖器座標與house座標求差值,找出這個house最小半徑。說白了,也是在查找house的最近左右取暖器,只是這種解法,很是清晰簡單,使人佩服。

public int findRadius(int[] houses, int[] heaters) {
    Arrays.sort(heaters);
    int result = 0;
    
    for (int house : houses) {
        int index = Arrays.binarySearch(heaters, house);
        if (index < 0) {
            index = ~index;
            int dist1 = index - 1 >= 0 ? house - heaters[index - 1] : Integer.MAX_VALUE;
            int dist2 = index < heaters.length ? heaters[index] - house : Integer.MAX_VALUE;
            
            result = Math.max(result, Math.min(dist1, dist2));
        }
    }
    
    return result;
}

測試用例:

public static void main(String[] args) {
    Solution s = new Solution();
    {
        int[] house = {1,2,3,4};
        int[] heaters = {1,4};
        assert(s.findRadius(house, heaters) == 1);
    }
    {
        int[] house = {1,5};
        int[] heaters = {10};
        assert(s.findRadius(house, heaters) == 9);
    }
    {
        int[] house = {1,2,3};
        int[] heaters = {2};
        assert(s.findRadius(house, heaters) == 1);
    }
    {
        int[] house = {7,9, 1};
        int[] heaters = {2};
        assert(s.findRadius(house, heaters) == 7);
    }
    {
        int[] house = {282475249,622650073,984943658,144108930,470211272,101027544,457850878,458777923};
        int[] heaters = {823564440,115438165,784484492,74243042,114807987,137522503,441282327,16531729,823378840,143542612};
        assert(s.findRadius(house, heaters) == 161834419);
    }
}
相關文章
相關標籤/搜索