力扣 | 1262. 可被三整除的最大和

92 篇文章 0 订阅
42 篇文章 0 订阅

前言

计算能被三整除的最大和


一、力扣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);

        
    }
};

总结

引用的地方还要在理解一遍,还是有问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值