跳转至

3281. 范围内整数的最大得分

题目描述

给你一个整数数组 start 和一个整数 d,代表 n 个区间 [start[i], start[i] + d]

你需要选择 n 个整数,其中第 i 个整数必须属于第 i 个区间。所选整数的 得分 定义为所选整数两两之间的 最小 绝对差。

返回所选整数的 最大可能得分

 

示例 1:

输入: start = [6,0,3], d = 2

输出: 4

解释:

可以选择整数 8, 0 和 4 获得最大可能得分,得分为 min(|8 - 0|, |8 - 4|, |0 - 4|),等于 4。

示例 2:

输入: start = [2,6,13,13], d = 5

输出: 5

解释:

可以选择整数 2, 7, 13 和 18 获得最大可能得分,得分为 min(|2 - 7|, |2 - 13|, |2 - 18|, |7 - 13|, |7 - 18|, |13 - 18|),等于 5。

 

提示:

  • 2 <= start.length <= 105
  • 0 <= start[i] <= 109
  • 0 <= d <= 109

解法

方法一:排序 + 二分查找

我们不妨先对 $\textit{start}$ 数组进行排序,然后我们考虑从左到右选择整数,那么得分就等于我们选择的相邻两个整数的差值的最小值。

如果一个差值 $x$ 满足条件,那么对于任意 $x' \lt x$,也一定满足条件。因此我们可以使用二分查找的方法来找到最大的满足条件的差值。

我们定义二分查找的左边界 $l = 0$,右边界 $r = \textit{start}[-1] + d - \textit{start}[0]$,然后我们每次取中间值 $mid = \left\lfloor \frac{l + r + 1}{2} \right\rfloor$,然后判断是否满足条件。

我们定义一个函数 $\text{check}(mi)$ 来判断是否满足条件,具体实现如下:

  • 我们定义一个变量 $\textit{last} = -\infty$,表示上一个选择的整数。
  • 我们遍历 $\textit{start}$ 数组,如果 $\textit{last} + \textit{mi} > \textit{st} + d$,那么说明我们无法选择整数 $\textit{st}$,返回 $\text{false}$。否则,我们更新 $\textit{last} = \max(\textit{st}, \textit{last} + \textit{mi})$。
  • 如果遍历完整个 $\textit{start}$ 数组都满足条件,那么返回 $\text{true}$。

时间复杂度 $O(n \times \log M)$,其中 $n$ 和 $M$ 分别是 $\textit{start}$ 数组的长度和最大值。空间复杂度 $O(1)$。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def maxPossibleScore(self, start: List[int], d: int) -> int:
        def check(mi: int) -> bool:
            last = -inf
            for st in start:
                if last + mi > st + d:
                    return False
                last = max(st, last + mi)
            return True

        start.sort()
        l, r = 0, start[-1] + d - start[0]
        while l < r:
            mid = (l + r + 1) >> 1
            if check(mid):
                l = mid
            else:
                r = mid - 1
        return l
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
    private int[] start;
    private int d;

    public int maxPossibleScore(int[] start, int d) {
        Arrays.sort(start);
        this.start = start;
        this.d = d;
        int n = start.length;
        int l = 0, r = start[n - 1] + d - start[0];
        while (l < r) {
            int mid = (l + r + 1) >>> 1;
            if (check(mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        return l;
    }

    private boolean check(int mi) {
        long last = Long.MIN_VALUE;
        for (int st : start) {
            if (last + mi > st + d) {
                return false;
            }
            last = Math.max(st, last + mi);
        }
        return true;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
    int maxPossibleScore(vector<int>& start, int d) {
        ranges::sort(start);
        auto check = [&](int mi) -> bool {
            long long last = LLONG_MIN;
            for (int st : start) {
                if (last + mi > st + d) {
                    return false;
                }
                last = max((long long) st, last + mi);
            }
            return true;
        };
        int l = 0, r = start.back() + d - start[0];
        while (l < r) {
            int mid = l + (r - l + 1) / 2;
            if (check(mid)) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        return l;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func maxPossibleScore(start []int, d int) int {
    check := func(mi int) bool {
        last := math.MinInt64
        for _, st := range start {
            if last+mi > st+d {
                return false
            }
            last = max(st, last+mi)
        }
        return true
    }
    sort.Ints(start)
    l, r := 0, start[len(start)-1]+d-start[0]
    for l < r {
        mid := (l + r + 1) >> 1
        if check(mid) {
            l = mid
        } else {
            r = mid - 1
        }
    }
    return l
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function maxPossibleScore(start: number[], d: number): number {
    start.sort((a, b) => a - b);
    let [l, r] = [0, start.at(-1)! + d - start[0]];
    const check = (mi: number): boolean => {
        let last = -Infinity;
        for (const st of start) {
            if (last + mi > st + d) {
                return false;
            }
            last = Math.max(st, last + mi);
        }
        return true;
    };
    while (l < r) {
        const mid = l + ((r - l + 1) >> 1);
        if (check(mid)) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }
    return l;
}

评论