Appearance
1877. 数组中最大数对和的最小值
ts
function minPairSumUpdate(nums: number[]): number {
nums.sort((a, b) => a - b)
let max = 0
const n = nums.length
for (let i = 0; i < n / 2; i++) {
const sum = nums[i] + nums[n - 1 - i]
if (sum > max) max = sum
}
return max
}这题要压的不是总和,而是所有配对里的最大值。目标一变,配对策略就很固定了:不能让大数和大数撞在一起,否则峰值会被直接抬高。
排序后首尾配对,本质是在做极值对冲。最小的去接最大的,次小的去接次大的,结果不是让每一对都最小,而是让最坏的那一对别太离谱。这个思路比“贪心”两个字本身更值得记。
为什么不是相邻配
如果把排好序的数组相邻配,比如 1,2,3,4 配成 (1,2) 和 (3,4),最大 pair sum 是 7。
首尾配 (1,4) 和 (2,3),最大 pair sum 变成 5。
这里实际在避免一件事:大的值聚集。只要大值集中在同一对里,答案就会被那一对决定。把大值拆开,分别交给小值去吸收,最大值才会下降。
换个更抽象的看法,设 a <= b <= c <= d:
- 相邻配时是
(a, b)和(c, d) - 首尾配时是
(a, d)和(b, c)
后一种配法不会让“较大的那个和”变得更差,通常还更小。局部成立,整体就自然落到双指针头尾配。
代码上没什么花样
排序后扫前半段,和后半段镜像位置配对就够了。
nums[i]nums[n - 1 - i]
每次更新当前最大的 pair sum,最后返回它。
初始版本用双指针 pre/aft 写也一样,只是 for 版更贴近这个题的结构,看起来负担更小。
一个小前提
这里 max 初始化成 0 是因为题目里的 nums[i] 都是正数。
如果题目允许负数,这种写法就不稳了,应该初始化成第一对的和,或者 -Infinity。
复杂度
- 时间复杂度:
O(n log n),主要是排序 - 空间复杂度:取决于排序实现,通常记作
O(log n)或语言相关
这题真正该留下来的只有一句话:
当目标是最小化“配对结果里的最大值”时,优先考虑把大值和小值绑定,而不是让相近量级的值聚在一起。
