1.题目
给你一个整数数组 nums,请你找出并返回能被三整除的元素最大和。
示例 1:
输入:nums = [3,6,5,1,8]
输出:18
解释:选出数字 3, 6, 1 和 8,它们的和是 18(可被 3 整除的最大和)。
示例 2:
输入:nums = [4]
输出:0
解释:4 不能被 3 整除,所以无法选出数字,返回 0。
示例 3:
输入:nums = [1,2,3,4,4]
输出:12
解释:选出数字 1, 3, 4 以及 4,它们的和是 12(可被 3 整除的最大和)。
提示:
1 <= nums.length <= 4 * 10^4
1 <= nums[i] <= 10^4
2.题解
这道题第一反应是贪心,但是我贪了半天才发现策略不对,而且复杂度还很高,因为只要贪就得排序,排序就是O(nlogn),而dp却只用O(n),题解也有贪的,但是我没看。
这道题只是在以往的基础上变了一丢丢我就不会了。我把这道题和全部子串联系在了一起,全部子串主要考虑的是要不要前一个数,而3的余数的话,这个数就不知道怎么处理了。其实就变了一点点。我只要拿三个数分别保存每种余数的情况下最大的和就可以了。例如一个3个元素的数组,分别代表余数为0、1和2的数字。最后如果新的结果大于原有的数据就更新。
这里我又遇到了一个很SB的问题,数组初始化是3个0,数组中第0个数是0没错,0%3=0,但是第1个数也是0,余数不是1,啊。差不多的问题,如果我上来给了10个9,9的余数都是0,就是说这些数都只能放在余数为0的那个数组了吗?拿结果肯定不对啊。后来我明白了,其实并不用管这个数是从余数为几的来的,只需要管这个数的结果就好。比如一组数是272,dp[]的初始值是000,第一轮过后结果肯定是002,第二轮的时候先算0+7=7,7的余数是1,所以放在dp[1],2+7=9,放在dp[0],第二轮结束就是9,7,2。第三轮就是9,7,11。
3.源码
int maxSumDivThree(vector<int>& nums) {
vector<int> ans(3, 0);
for (auto num : nums)
{
int mod = num % 3;
vector<int>temp(ans.begin(), ans.end());
for (auto numtemp : ans)
{
int a = (numtemp + num);
temp[a % 3] = max(temp[a % 3], a);
}
ans = temp;
}
return ans[0];
}