题目描述
给你一个整数数组 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;
}
|