给你一个整数数组 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
解题思路
可以这样思考,遍历整个数组然后将数分成三个部分,%3==0
、%3==1
和%3==2
。
然后整个数组的和sum_all
模3
等于0
,那么这就是最大值了。
如果等于1
,那么我们需要从%3==1
的数中选一个最小的数t1
,然后再从%3==2
中选两个最小的数并计算和t2
,比较t1
和t2
选择最小的,然后sum_all
减去即可。
如果等于2
,那么我们需要从%3==2
的数中选一个最小的数t1
,然后再从%3==1
中选两个最小的数并计算和t2
,比较t1
和t2
选择最小的,然后sum_all
减去即可。
class Solution:
def maxSumDivThree(self, nums: List[int]) -> int:
b0, b1, b2 = [], [], []
sum_all = 0
for i in nums:
if i % 3 == 0:
b0.append(i)
elif i % 3 == 1:
b1.append(i)
else:
b2.append(i)
sum_all += i
if sum_all % 3 == 0:
return sum_all
elif sum_all % 3 == 1:
t1, t2 = 0, 0
if len(b1): t1 = sum_all - min(b1)
if len(b2) > 1: t2 = sum_all - sum(sorted(b2)[:2])
return max(t1, t2)
else:
t1, t2 = 0, 0
if len(b2): t1 = sum_all - min(b2)
if len(b1) > 1:t2 = sum_all - sum(sorted(b1)[:2])
return max(t1, t2)
使用动态规划更加简洁。定义 f ( i , j ) f(i,j) f(i,j)表示到nums[i]
为止满足sum%3==j
的最大sum
是多少,那么
nums[i]%3==0
: f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i − 1 , j ) + n u m s [ i − 1 ] ) f(i,j)=max(f(i-1,j),f(i-1,j)+nums[i-1]) f(i,j)=max(f(i−1,j),f(i−1,j)+nums[i−1])nums[i]%3==1
: f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i − 1 , ( j + 2 ) % 3 ) + n u m s [ i − 1 ] ) f(i,j)=max(f(i-1,j), f(i-1,(j+2)\%3)+nums[i-1]) f(i,j)=max(f(i−1,j),f(i−1,(j+2)%3)+nums[i−1])nums[i]%3==2
: f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i − 1 , ( j + 1 ) % 3 ) + n u m s [ i − 1 ] ) f(i,j)=max(f(i-1,j),f(i-1,(j+1)\%3)+nums[i-1]) f(i,j)=max(f(i−1,j),f(i−1,(j+1)%3)+nums[i−1])所以可以推出
还需要注意的一点是,当且仅当上面式子中 f ( i − 1 , ( j + 3 − n u m s [ i − 1 ] % 3 ) % 3 ) + n u m s [ i − 1 ] % = = j f(i-1,(j+3-nums[i-1]\%3)\%3)+nums[i-1]\%==j f(i−1,(j+3−nums[i−1]%3)%3)+nums[i−1]%==j的时候式子才成立。
class Solution:
def maxSumDivThree(self, nums: List[int]) -> int:
n = len(nums)
dp = [[0]*3 for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(3):
a = dp[i - 1][(j + 3 - nums[i-1]%3) % 3] + nums[i-1]
if a % 3 == j:
dp[i][j] = max(dp[i-1][j], a)
else:
dp[i][j] = dp[i-1][j]
return dp[-1][0]
还可以更加简洁。定义 f ( i ) f(i) f(i)表示当前满足sum%3==i
的最大sum
是多少,那么
其中a
表示nums
中的每个数。
class Solution:
def maxSumDivThree(self, nums: List[int]) -> int:
dp = [0, 0, 0]
for a in nums:
for i in dp[:]:
dp[(i + a) % 3] = max(dp[(i + a) % 3], i + a)
return dp[0]
reference:
https://leetcode.com/problems/greatest-sum-divisible-by-three/discuss/431077/Python-One-Pass-O(1)-space
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!