LeetCode163周赛第三题——1262. 可被三整除的最大和

1262. 可被三整除的最大和

题目描述

给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和。

示例

示例1

输入:nums = [3,6,5,1,8]
输出:18
解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。

示例2

输入:nums = [4]
输出:0
解释:4 不能被 3 整除,所以无法选出数字,返回 0。

题目分析1

一个直观的思路就是根据num[i]%3讲数字分成三组,list0(余数为0),list1(余数为1),list2(余数为2),然后求出数组的总和sum,那么:

  • 当sum%3=1时,我们需要删除list1的最小值sum1,或者list2两个最小值,和为sum2,删除sum1、sum2中的最小值
  • 当sum%3=2时,我们需要删除list2的最小值sum2,或者list1两个最小值,和为sum1,删除sum1、sum2中的最小值

java代码

public int maxSumDivThree(int[] nums) {
        List<Integer> list = new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            list.add(nums[i]);
        }
        list.sort(Integer::compareTo);
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        List<Integer> list0 = new ArrayList<>();
        int sum = 0;
        for(int i=0;i<list.size();i++){
            int x = list.get(i);
            sum += x;
            if(x%3==0){
                list0.add(x);
            }else if(x%3==1){
                list1.add(x);
            }else{
                list2.add(x);
            }
        }
        int sum1 = Integer.MAX_VALUE;
        int sum2 = Integer.MAX_VALUE;
        if(sum%3 == 1){
            if(list1.size()>=1){
                sum1 = list1.get(0);
            }
            if(list2.size()>=2){
                sum2 = list2.get(0)+list2.get(1);
            }
            if(sum1 != Integer.MAX_VALUE || sum2 != Integer.MAX_VALUE){
                sum -= (sum1<sum2?sum1:sum2);
            }else{
                sum = 0;
            }
        }else if(sum%3==2){
            if(list1.size()>=2){
                sum1 = list1.get(0)+list1.get(1);
            }
            if(list2.size()>=1){
                sum2 = list2.get(0);
            }
            if(sum1 != Integer.MAX_VALUE || sum2 != Integer.MAX_VALUE){
                sum -= (sum1<sum2?sum1:sum2);
            }else{
                sum = 0;
            }
        }
        return sum;
    }

题目分析2

我们可以使用动态规划来解决这个问题,dp[i]表示 选取数字累加和 mod3=i 的数字和,那么

  • 如果num[i]%3=1
    1.dp[0] = max(dp[0],num[i]+dp[2])
    2.dp[1] = max(dp[1],num[i]+dp[0])
    3.dp[2] = max(dp[2],num[i]+dp[1])
  1. 如果num[i]%3=2
    1.dp[0] = max(dp[0],num[i]+dp[1])
    2.dp[1] = max(dp[1],num[i]+dp[2])
    3.dp[2] = max(dp[2],num[i]+dp[0])
  2. 如果num[i]%3=0
    1.dp[0] = max(dp[0],num[i]+dp[0])
    2.dp[1] = max(dp[1],num[i]+dp[1])
    3.dp[2] = max(dp[2],num[i]+dp[2])

综上所述,设num[i]%3=k,那么

  • dp[0] = max(dp[0],num[i]+dp[(3 + 0 -k)%3])
  • dp[1] = max(dp[1],num[i]+dp[(3 + 1 -k)%3])
  • dp[2] = max(dp[2],num[i]+dp[(3 + 2 -k)%3])

转移方程已经确定,下面给出代码

java代码

public int maxSumDivThree(int[] nums) {
        int[] dp = new int[]{0,0,0};

        for(int i=0;i<nums.length;i++){
            int k = nums[i]%3;
            // 找到与k对应的dp[i]的i值,因为每一次添加一个数字,三个dp值都要更新
            int a = dp[(3 + 0 - k) % 3];// (a+k)%3=0 ==> (a+num[i])%3=0
            int b = dp[(3 + 1 - k) % 3];// (b+k)%3=1 ==> (b+num[i])%3=1
            int c = dp[(3 + 2 - k) % 3];// (c+k)%3=2 ==> (c+num[i])%3=2
            if(a!=0 || k==0) {
                dp[0] =Math.max(dp[0],a+nums[i]);
            }
            if(b!=0 || k==1){
                dp[1] = Math.max(dp[1],b+nums[i]);
            }
            if(c!=0 || k==2){
                dp[2] = Math.max(dp[2],c+nums[i]);
            }
        }
        return dp[0];
    }

你可能感兴趣的:(周赛,LeetCode)