Medium
题目描述
给你一个整数数组 nums。
你的任务是从 nums 中恰好选择三个整数,使得它们的和能被三整除。
返回这样的三元组的最大可能和。如果不存在这样的三元组,返回 0。
示例 1:
输入:nums = [4,2,3,1]
输出:9
解释:
和能被 3 整除的有效三元组有:
- (4, 2, 3),和为 4 + 2 + 3 = 9
- (2, 3, 1),和为 2 + 3 + 1 = 6
因此,答案是 9。
示例 2:
输入:nums = [2,1,5]
输出:0
解释:
没有三元组的和能被 3 整除,所以答案是 0。
约束条件:
3 <= nums.length <= 10^51 <= nums[i] <= 10^5
解题思路
解题思路
这是一道关于数学性质和贪心算法的题目。关键在于理解三个数的和能被3整除的条件。
核心观察
根据模运算的性质,三个数的和能被3整除,当且仅当这三个数对3取模的结果之和能被3整除。设三个数分别为 a, b, c,它们对3取模的结果为 a%3, b%3, c%3,那么 (a+b+c)%3 = (a%3 + b%3 + c%3)%3。
有效组合
对于三个数的模值组合,只有以下四种情况能使和被3整除:
- (0, 0, 0) - 三个数都能被3整除
- (1, 1, 1) - 三个数模3都余1
- (2, 2, 2) - 三个数模3都余2
- (0, 1, 2) - 三个数分别模3余0、1、2
算法步骤
- 将数组按照对3取模的结果分成三组:mod0、mod1、mod2
- 对每组按降序排列,确保优先选择最大的数
- 对于每种有效组合,尝试选择对应组中的最大值:
- 组合1:选择mod0中最大的3个数
- 组合2:选择mod1中最大的3个数
- 组合3:选择mod2中最大的3个数
- 组合4:分别选择mod0、mod1、mod2中的最大数
- 返回所有可能组合中的最大和
这种方法的时间复杂度为O(n log n),主要消耗在排序上;空间复杂度为O(n),用于存储分组。
代码实现
class Solution {
public:
int maximumSum(vector<int>& nums) {
vector<int> mod0, mod1, mod2;
for (int num : nums) {
if (num % 3 == 0) mod0.push_back(num);
else if (num % 3 == 1) mod1.push_back(num);
else mod2.push_back(num);
}
sort(mod0.rbegin(), mod0.rend());
sort(mod1.rbegin(), mod1.rend());
sort(mod2.rbegin(), mod2.rend());
int maxSum = 0;
// Case 1: 0 + 0 + 0
if (mod0.size() >= 3) {
maxSum = max(maxSum, mod0[0] + mod0[1] + mod0[2]);
}
// Case 2: 1 + 1 + 1
if (mod1.size() >= 3) {
maxSum = max(maxSum, mod1[0] + mod1[1] + mod1[2]);
}
// Case 3: 2 + 2 + 2
if (mod2.size() >= 3) {
maxSum = max(maxSum, mod2[0] + mod2[1] + mod2[2]);
}
// Case 4: 0 + 1 + 2
if (!mod0.empty() && !mod1.empty() && !mod2.empty()) {
maxSum = max(maxSum, mod0[0] + mod1[0] + mod2[0]);
}
return maxSum;
}
};
class Solution:
def maximumSum(self, nums: List[int]) -> int:
mod0, mod1, mod2 = [], [], []
for num in nums:
if num % 3 == 0:
mod0.append(num)
elif num % 3 == 1:
mod1.append(num)
else:
mod2.append(num)
mod0.sort(reverse=True)
mod1.sort(reverse=True)
mod2.sort(reverse=True)
max_sum = 0
# Case 1: 0 + 0 + 0
if len(mod0) >= 3:
max_sum = max(max_sum, mod0[0] + mod0[1] + mod0[2])
# Case 2: 1 + 1 + 1
if len(mod1) >= 3:
max_sum = max(max_sum, mod1[0] + mod1[1] + mod1[2])
# Case 3: 2 + 2 + 2
if len(mod2) >= 3:
max_sum = max(max_sum, mod2[0] + mod2[1] + mod2[2])
# Case 4: 0 + 1 + 2
if mod0 and mod1 and mod2:
max_sum = max(max_sum, mod0[0] + mod1[0] + mod2[0])
return max_sum
public class Solution {
public int MaximumSum(int[] nums) {
List<int> mod0 = new List<int>();
List<int> mod1 = new List<int>();
List<int> mod2 = new List<int>();
foreach (int num in nums) {
if (num % 3 == 0) mod0.Add(num);
else if (num % 3 == 1) mod1.Add(num);
else mod2.Add(num);
}
mod0.Sort((a, b) => b.CompareTo(a));
mod1.Sort((a, b) => b.CompareTo(a));
mod2.Sort((a, b) => b.CompareTo(a));
int maxSum = 0;
// Case 1: 0 + 0 + 0
if (mod0.Count >= 3) {
maxSum = Math.Max(maxSum, mod0[0] + mod0[1] + mod0[2]);
}
// Case 2: 1 + 1 + 1
if (mod1.Count >= 3) {
maxSum = Math.Max(maxSum, mod1[0] + mod1[1] + mod1[2]);
}
// Case 3: 2 + 2 + 2
if (mod2.Count >= 3) {
maxSum = Math.Max(maxSum, mod2[0] + mod2[1] + mod2[2]);
}
// Case 4: 0 + 1 + 2
if (mod0.Count > 0 && mod1.Count > 0 && mod2.Count > 0) {
maxSum = Math.Max(maxSum, mod0[0] + mod1[0] + mod2[0]);
}
return maxSum;
}
}
var maximumSum = function(nums) {
const mod0 = [], mod1 = [], mod2 = [];
for (let num of nums) {
if (num % 3 === 0) mod0.push(num);
else if (num % 3 === 1) mod1.push(num);
else mod2.push(num);
}
mod0.sort((a, b) => b - a);
mod1.sort((a, b) => b - a);
mod2.sort((a, b) => b - a);
let maxSum = 0;
// Case 1: three numbers from mod0
if (mod0.length >= 3) {
maxSum = Math.max(maxSum, mod0[0] + mod0[1] + mod0[2]);
}
// Case 2: one from mod0, one from mod1, one from mod2
if (mod0.length >= 1 && mod1.length >= 1 && mod2.length >= 1) {
maxSum = Math.max(maxSum, mod0[0] + mod1[0] + mod2[0]);
}
// Case 3: three from mod1
if (mod1.length >= 3) {
maxSum = Math.max(maxSum, mod1[0] + mod1[1] + mod1[2]);
}
// Case 4: three from mod2
if (mod2.length >= 3) {
maxSum = Math.max(maxSum, mod2[0] + mod2[1] + mod2[2]);
}
return maxSum;
};
复杂度分析
| 复杂度类型 | 值 |
|---|---|
| 时间复杂度 | O(n log n) |
| 空间复杂度 | O(n) |
说明:
- 时间复杂度:O(n log n),主要消耗在对三个分组数组进行排序
- 空间复杂度:O(n),用于存储按模值分组的三个数组