1262. 可被三整除的最大和
大约 4 分钟
---
1262. 可被三整除的最大和
- 标签:贪心、数组、动态规划、排序
- 难度:中等
题目链接
题目大意
描述:给你一个整数数组 ,你需要从数组中选出一些数(可以不选),使得这些数的和能被 整除。
要求:找出并返回能被三整除的最大和。
说明:
- 。
- 。
示例:
- 示例 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:动态规划
1. 阶段划分
依次处理数组中的每个数字,每来一个数字,我们都决定是否选取它。这种「选或不选」的决策天然适合动态规划。
2. 定义状态
定义 表示当前已经处理过的数字中,能够得到的、模 的余数为 的最大和,其中 。
例如 表示当前能得到的模 余 的最大和, 表示模 余 的最大和, 表示模 余 的最大和。
3. 状态转移方程
对于当前数字 ,记 。我们需要考虑:把 加到已有的各个余数状态上,会得到新的余数。
对于每个已有状态 (),如果 (表示该状态可达):
- 新余数 =
- 新和 =
- 更新
同时,不选 的情况也需要保留,所以 至少等于 。
4. 初始条件
不选取任何数时,和为 ,模 余 ,所以 。
和 都无法达到,初始化为 。
5. 最终结果
就是模 余 的最大和,即能被 整除的最大和。
结合示例 1 走一遍:
初始化:
- :,新余数 →
- :,新余数 →
- :,新余数 →
- :
- ,新余数 →
- ,新余数 → →
- :
- ,新余数 →
- ,新余数 →
- ,新余数 →
结果 ... 但这和示例答案 不一致。让我重新检查。
啊,我明白了。上面的过程中,我处理每个数字的方式不对。当 时,,但原来 ,所以我们需要保留「不选」的情况。
正确的做法是在更新时使用备份数组,或者同时考虑选与不选。
让我重新来处理:
初始化:
对于 :
- ,复制为
- :
- :跳过()
- :跳过()
对于 :
- ,复制为
- :
对于 :
- ,复制为
- :
对于 :
- ,复制为
- :
- :
对于 :
- ,复制为
- :
- :
- :
结果 ✓
好的,这个示例的计算过程可以不用在文件中写太细,但需要保证解释清晰。
思路 1:代码
class Solution:
def maxSumDivThree(self, nums: List[int]) -> int:
# dp[r] 表示当前能得到的模 3 余 r 的最大和
# -1 表示该状态暂时不可达
dp = [-1, -1, -1]
dp[0] = 0
for num in nums:
r = num % 3
# 复制当前状态,用于同时处理所有转移
new_dp = dp[:]
for i in range(3):
if dp[i] != -1:
# 将 num 加入余数为 i 的状态
new_r = (i + r) % 3
new_dp[new_r] = max(new_dp[new_r], dp[i] + num)
dp = new_dp
return dp[0]思路 1:复杂度分析
- 时间复杂度:,其中 是数组 的长度。每个数字只需要 时间处理( 个状态的更新)。
- 空间复杂度:,只使用了一个长度为 的数组。