Easy
题目描述
给定长度为 2n 的整数数组 nums,你的任务是将这些整数分成 n 对 (a1, b1), (a2, b2), …, (an, bn),使得从 1 到 n 的 min(ai, bi) 总和最大。返回该最大总和。
示例 1:
输入:nums = [1,4,3,2]
输出:4
解释:所有可能的分对(忽略元素顺序)为:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
所以最大可能的总和是 4。
示例 2:
输入:nums = [6,2,6,5,1,2]
输出:9
解释:最优分对是 (2, 1), (2, 5), (6, 6)。min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9。
约束条件:
- 1 <= n <= 10^4
- nums.length == 2 * n
- -10^4 <= nums[i] <= 10^4
解题思路
解题思路
核心观察:要使所有对的最小值之和最大,我们需要让每个较小的数都尽可能大。
关键洞察:
- 在每一对 (a, b) 中,较小的数会被选入结果,较大的数会被"牺牲"掉
- 为了最大化总和,我们应该让被牺牲的数尽可能小
- 这意味着我们应该将相邻的数配对
算法步骤:
- 将数组排序
- 选择所有偶数索引位置的元素(即第 0, 2, 4, … 个元素)
- 这些元素的和就是答案
为什么这样做是最优的:
- 排序后,每个偶数位置的元素都与其右邻居配对
- 由于数组有序,偶数位置的元素必然是这一对中的较小值
- 这种配对方式确保了较大的数只会牺牲掉比它小的最接近的数,从而最大化了总和
时间复杂度分析:排序需要 O(n log n),遍历需要 O(n),总体为 O(n log n)。
代码实现
class Solution {
public:
int arrayPairSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int sum = 0;
for (int i = 0; i < nums.size(); i += 2) {
sum += nums[i];
}
return sum;
}
};
class Solution:
def arrayPairSum(self, nums: List[int]) -> int:
nums.sort()
return sum(nums[::2])
public class Solution {
public int ArrayPairSum(int[] nums) {
Array.Sort(nums);
int sum = 0;
for (int i = 0; i < nums.Length; i += 2) {
sum += nums[i];
}
return sum;
}
}
var arrayPairSum = function(nums) {
nums.sort((a, b) => a - b);
let sum = 0;
for (let i = 0; i < nums.length; i += 2) {
sum += nums[i];
}
return sum;
};
复杂度分析
| 复杂度类型 | 大小 |
|---|---|
| 时间复杂度 | O(n log n) |
| 空间复杂度 | O(1) |