774. Minimize Max Distance to Gas Station

On a horizontal number line, we have gas stations at positions stations[0], stations[1], ..., stations[N-1], where N = stations.length. Now, we add K more
 gas stations so that D, the maximum distance between adjacent gas stations, is minimized. Return the smallest possible value of D.
Example:
Input: stations = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], K = 9
Output: 0.500000
Note:
stations.length will be an integer in range [10, 2000].
stations[i] will be an integer in range [0, 10^8].
K will be an integer in range [1, 10^6].
Answers within 10^-6 of the true value will be accepted as correct.
例子:
1  ⛽️   2  ⛽️   3  ⛽️   4  ⛽️   5  ⛽️   6  ⛽️   7  ⛽️   8  ⛽️   9  ⛽️   10
放中间, minimized max distance is 0.5
其他情况, 举个最极端的
1     2     3     4     5  ⛽️…⛽️   6     7     8     9     
全部放中间,虽然中间加油站之间的distance 是0.1 ,但是minimized最大的distance 还是1    





再举个例子:
1          3           8   K = 3
1          3    ⛽5.5   8
1          3    ⛽5.5  ⛽️6.75    8
1    ⛽️2      3    ⛽️5.5   ⛽️6.75   8

思路:每一次我们选用最大的距离,取中点一分为二。假如需要插入多个加油站,那么均分一段距离可以保证油站之间距离最大

我们可不可以继续借用exam room interval 的方法?

Solution 1:
我们把每个油站之间的距离保存到数据结构。每次把最大平均距离的interval 拿出来,再加一个油站。那么这段interval之间的距离就会减小
数据结构:priorityqueue
Time: O(KlogN)
Space: O(N) -- where n is the length of stations and K is new gas stations to be added

public double minmaxGasDist(int[] stations, int K) {
        if (stations == null || stations.length == 0) return 0.0;
        PriorityQueue<Interval> maxHeap = new PriorityQueue<>(new Comparator<Interval>(){
            @Override
            public int compare(Interval i1, Interval i2) {
                return (double)i1.distance/i1.stops < (double)i2.distance/i2.stops ? 1:-11;
            }
        });
        
        for (int i = 0; i < stations.length - 1; i++) {
            maxHeap.offer(new Interval(stations[i + 1] - stations[i], 1));
        }
        
        while (K > 0) {
            Interval cur = maxHeap.poll();
            cur.stops++;
            maxHeap.offer(cur);
            K--;
        }
        Interval res = maxHeap.poll();
        return (double)res.distance/res.stops;
    }
    class Interval {
        int distance;
        int stops;
        public Interval(int distance, int stops) {
            this.distance = distance;
            this.stops = stops;
        }
    }


Solution 2:
Binary Search

1.解函数的sorted性质
解空间maximum distance between adjacent gas stations: 
 [1  x  2  x  3  x  4  x  5  x  6  x  7  x    x  9  x 10]
0  0.1  0.2  x  x  x min_distance(0.5)  0.6  0.7  y  y  y  1.0
其中xxx均是达不到的,yyy均是可实现的

2.函数模型
f(i): 在N个stations之间最多再添加K个stations,使得任意两个stations之间的距离 <= i 吗?
即: f(x) = false  f(y) = true 
我们要做的就是找到第一个y

3.search range: 
确定边界条件 [0, stations[stations.length - 1] - stations[0]]  
更准确的是: K = 0的时候,上边界是max(stations[i] - stations[i - 1]), 0 < i < stations.length
            K = +infinite的时候,下边界趋近于0
mid: 假设我们固定一个mid值 来尝试寻找是否能满足最多添加K个stations,使得任意两个stations之间的距离 <= mid
How to narrow the search range without missing correct answer?
If the current mid can be a solution, then we search on the lower half, 
else we search in higher half. (因为f(i)是单调的)


4.check function
now the question becomes to how to check if a mid value is feasible or not? 最难的一步
⇔ sliding window problem
0   1   2   3   4   5
x    x   x   x   x   x

stations[1] - stations[0] = distance
case1: distance = mid  -> do nothing
case2: distance < mid  -> do nothing
case3: distance > mid 
-> 需要在station 1和station 0添加多少个stations,才能使得任意两个间的distance <= mid?
    -> Math.ceil(distance / mid) - 1 ⇔ (int)(distance / mid)

Time: O(nlogm) - m the length of max interval
Space: O(1)
(0, stations[stations.length - 1] - stations[0])
    ------------------------------------------
    0     3             7                          18
int 32  2^64

public double minmaxGasDist(int[] stations, int K) {
        if (stations == null || stations.length == 0) return 0.0;
        double start = 0;
        double end = stations[stations.length - 1] - stations[0];
        double eps = 1e-6;
        while (start + eps < end) {
            double mid = start+ (end - start)/2;
            if (checkFeasible(stations, K, mid)) {
                end = mid;
            } else {
                start = mid;
            }
        }
        return start;
    }

    private boolean checkFeasible(int[] stations, int K, double mid) {
        int count = 0;
        for (int i = 0; i < stations.length - 1; i++) {
            count += Math.ceil((stations[i + 1] - stations[i])/mid) - 1;
            if (count > K) return false;
        }
        
        return true;
    }

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9697634.html