前言
计算能被三整除的最大和
一、力扣1262
要求:计算能被三整除的最大和。
给定数组,数组元素都是正数,要求实现尽可能被3整除的元素之和最大
二、正面下手
把数组(nums)元素分为三类:
1.被三整除 总共个数有a
2.被三除了之后余1 总共个数有b
3.被三除了之后余2 总共个数有c
a + b + c = nums.size()
第一类最后处理
第二类和第三类有一个特点,
这是数字的特点,想弄清楚原理的,那要看数论
结论是这样的:( cntb(b中个个数)+ cntc(c中的个数) )% 3 ==(cntb - cntc) %3 == 0
条件是 cntb 和cntc 模3余数是一样的
`我们希望上式的值为 000,那么 cntb\textit{cnt}_bcnt
b
和 cntc\textit{cnt}_ccnt
c
模 333 同余。并且我们可以发现,cntb\textit{cnt}_bcnt
b
一定至少为 ∣b∣−2|b| - 2∣b∣−2,其中 ∣b∣|b|∣b∣ 是数组 bbb 中的元素个数。这是因为如果 cntb≤∣b∣−3\textit{cnt}_b \leq |b| - 3cnt
b
≤∣b∣−3,我们可以继续在 bbb 中选择 333 个数,使得 cntb\textit{cnt}_bcnt
b
和 cntc\textit{cnt}_ccnt
c
仍然模 333 同余。同理,cntc\textit{cnt}_ccnt
c
一定至少为 ∣c∣−2|c| - 2∣c∣−2。
因此,cntb\textit{cnt}_bcnt
b
的选择范围一定在 {∣b∣−2,∣b∣−1,∣b∣}{ |b|-2, |b|-1, |b| }{∣b∣−2,∣b∣−1,∣b∣} 中,cntc\textit{cnt}_ccnt
c
的选择范围一定在 {∣c∣−2,∣c∣−1,∣c∣}{ |c|-2, |c|-1, |c| }{∣c∣−2,∣c∣−1,∣c∣} 中。我们只需要使用两重循环,枚举最多 3×3=93 \times 3 = 93×3=9 种情况。在从 bbb 或 ccc 中选取数时,我们可以贪心地从大到小选取数,因此需要对 bbb 和 ccc 进行排序。
`
1.题解
代码如下(示例):
class Solution {
public:
// 3,6, 1,5,8 b 被3取余为1的数: 1 4 7 10 13 cntb个数
// 0 0 1 2 2 c 被3取余为2的数: 2 5 8 11 14 cntc个数
// 其实每一个b中的数加上c中的每一个数之和就是3的倍数
// 但要求 (cntb + 2 * cntc) % 3 == (cntb - cntb) % 3 == 0
// 结论就是 cntb和cntc模3同余
// x x b c c
// 23 ;
// 22 20 18
int maxSumDivThree(vector<int>& nums) {
vector<int> v[3]; //v[0] v[1] v[2]
for(int num: nums){
v[num % 3].push_back(num);
}
sort(v[1].begin(), v[1].end(), greater<int>()); //按照从大到小的顺序排序 less则是从小到大
sort(v[2].begin(), v[2].end(), greater<int>());
int ans = 0;
int b = v[1].size(), c = v[2].size(); //分别获得取模为 1 2的总数
for(int cntb = b - 2; cntb <= b; ++cntb){
if(cntb >= 0){
for(int cntc = c - 2; cntc <= c; ++cntc){
if(cntc >=0 && (cntb - cntc) % 3 == 0){
ans = max(ans, accumulate(v[1].begin(), v[1].begin() + cntb, 0) + accumulate(v[2].begin(), v[2].begin() + cntc, 0));
}
}
}
}
return ans + accumulate(v[0].begin(), v[0].end(), 0);
}
};
总结
引用的地方还要在理解一遍,还是有问题。