2025-04-13:范围内整数的最大得分。用go语言,给定一个整数数组 start 和一个整数 d,这代表了 n 个区间 [start[i], start[i] + d]。你的任务是从每个区间中选择一个整数,使得所选整数之间的最小绝对差值尽可能大。返回所选整数能够得到的最大最小绝对差值。
2 <= start.length <= 100000。
0 <= start[i] <= 1000000000。
0 <= d <= 1000000000。
输入: start = [6,0,3], d = 2。
输出: 4。
解释:
可以选择整数 8, 0 和 4 获得最大可能得分,得分为 min(|8 - 0|, |8 - 4|, |0 - 4|),等于 4。
题目来自leetcode3280。
根据题目描述和提供的代码,解决该问题的步骤如下:
步骤解析
-
排序预处理
首先对输入的
start
数组进行排序。排序后区间顺序被调整为升序排列,便于后续的贪心策略按顺序处理每个区间。例如,输入[6,0,3]
排序后变为[0,3,6]
,对应的区间是[0,2]
、[3,5]
、[6,8]
。 -
二分搜索框架
目标是找到最大的最小绝对差值(记为
score
)。采用二分法确定该值:• 初始范围 :二分的上限设为
(start[n-1] + d - start[0]) / (n-1)
。这假设所有区间均匀分布时的最大可能差值。例如,当区间总长度为(8-0)=8
且n=3
时,初始上限为8/2=4
,与样例输出一致。• 验证函数 :对每个候选的
score
,判断是否能在所有区间中选出满足条件的数。若存在,尝试更大的score
;否则减小。 -
贪心验证策略
在每次二分验证时,从第一个区间开始,依次为每个区间选择尽可能小的数,同时满足以下条件:
• 当前数必须大于等于区间左端点(即
≥start[i]
)。• 当前数与前一个数的差值至少为
score
。具体实现中,变量
x
记录前一个区间的选择,每次更新为max(x+score, start[i])
。若此值超过区间右端点(start[i]+d
),则说明当前score
过大,验证失败。 -
边界处理
当所有区间均满足条件时,返回
true
,表示可以尝试更大的score
;否则返回false
。最终通过二分逼近最大的可行score
。
复杂度分析
• 时间复杂度 :
• 排序 :时间复杂度为O(n log n)
,其中n
为start
数组长度。
• 二分验证 :每次验证需要遍历n
个区间,时间复杂度O(n)
。二分次数为O(log C)
(C
为可能的score
最大值,如1e9
)。
总时间复杂度 :O(n log n + n log C)
,适用于n ≤ 1e5
的规模。
• 空间复杂度 :
仅需常数空间存储变量和排序(原地排序),因此总空间复杂度为O(1)
。
关键点
• 贪心策略的有效性 :通过按序处理区间并尽量选择最小的数,确保后续区间有更大的选择空间,从而最大化最小差值。
• 二分法的应用 :将最优化问题转化为判定问题,通过高效验证函数快速收敛到最优解。
• 初始范围的合理性:通过均匀分布假设设定二分上限,避免无效搜索。
Go完整代码如下:
go
package main
import (
"fmt"
"slices"
"sort"
"math"
)
func maxPossibleScore(start []int, d int) int {
slices.Sort(start)
n := len(start)
// 二分最小的不满足要求的 score+1,最终得到的答案就是最大的满足要求的 score
return sort.Search((start[n-1]+d-start[0])/(n-1), func(score int) bool {
score++
x := math.MinInt
for _, s := range start {
x = max(x+score, s) // x 必须 >= 区间左端点 s
if x > s+d {
return true
}
}
return false
})
}
func main() {
start := []int{6,0,3}
d := 2
results := maxPossibleScore(start,d)
fmt.Println(results)
}

Python完整代码如下:
python
# -*-coding:utf-8-*-
import math
def maxPossibleScore(start, d):
start.sort()
n = len(start)
if n == 1:
return 0
end = (start[-1] + d - start[0]) // (n - 1)
left, right = 0, end
ans = 0
while left <= right:
mid = (left + right) // 2
score_plus_1 = mid + 1
x = -math.inf
possible = True
for s in start:
x = max(x + score_plus_1, s)
if x > s + d:
possible = False
break
if not possible:
right = mid - 1
ans = mid
else:
left = mid + 1
return ans
# 测试示例
start = [6, 0, 3]
d = 2
print(maxPossibleScore(start, d)) # 输出结果为3
