LeetCode 1262. 可被三整除的最大和
题目描述

题意分析
从正整数数组中任意选择一些元素,使它们的和能被
3整除,并且这个和尽可能大。每个位置最多选一次,不要求所选元素在数组中连续。可以一个元素也不选,空集的和为
0,因此答案始终存在。判断能否被三整除只需要余数,而最大化目标又要求保留具体的和,可以把所有候选子集按余数0、1、2分成三类维护。
解法:按余数维护最大和动态规划
核心思路
[!blue]
令
dp[r]表示只使用已经处理过的元素,能够得到的余数为r的最大和。对余数相同的两个和,只保留较大者就足够:以后再选择相同的一组元素,两者的余数变化完全一样,较大的和仍然更大,所以较小者不可能产生更优答案。初始还没有处理任何元素,只有空集可选,因此
dp[0] = 0,另外两个余数不可达,用-1标记。输入都是正数,真实可达和不会为负,能够与这个标记明确区分;不可达状态不能参与加法转移。处理当前值
num时,先复制dp得到next,保留不选它的全部结果。然后枚举每个可达旧状态dp[r],计算选择后的sum = dp[r] + num,用它更新next[sum % 3]的最大值。这样选与不选两种可能都被覆盖,同余状态继续只保留最大和。所有选择转移必须读取同一份旧
dp。如果直接读写一个数组,本轮刚加入num的新状态可能再次加上num,就把一个位置重复使用了。Java 的clone()和 Go 的固定数组赋值都创建本轮快照,写next不会影响正在读取的旧状态。一轮结束后再令
dp = next,使状态对应多处理了一个元素的前缀。每个位置只贡献一次选或不选,且每类状态都保留最优和;遍历结束后只返回余数为零的dp[0],不能返回另外两类中更大但不能整除的值。
解题步骤
- 初始化三个余数状态为
0、-1、-1。- 对每个
num,复制旧状态得到next,表示先保留不选择它的方案。- 枚举
r = 0, 1, 2,跳过负值标记的不可达状态。- 计算
sum = dp[r] + num,用较大值更新next[sum % 3]。- 全部旧状态转移完后令
dp = next,继续处理下一个元素。- 返回最终的
dp[0]。
代码实现
class Solution {
public int maxSumDivThree(int[] nums) {
int[] dp = {
0,
-1,
-1
};
for (int num : nums) {
// 先保留不选当前元素的状态,所有选择转移只读取旧数组。
int[] next = dp.clone();
for (int r = 0; r < 3; r++) {
// 不可达余数没有真实子集,不能参与加法转移。
if (dp[r] < 0) {
continue;
}
int sum = dp[r] + num;
int remainder = sum % 3;
next[remainder] = Math.max(next[remainder], sum);
}
dp = next;
}
return dp[0];
}
}
func maxSumDivThree(nums []int) int {
dp := [3]int{
0,
-1,
-1,
}
for _, num := range nums {
// 固定数组按值复制,所有选择转移只读取旧状态。
next := dp
for r := 0; r < 3; r++ {
// 不可达余数没有真实子集,不能参与加法转移。
if dp[r] < 0 {
continue
}
sum := dp[r] + num
remainder := sum % 3
if sum > next[remainder] {
next[remainder] = sum
}
}
dp = next
}
return dp[0]
}
复杂度分析
- 时间复杂度:$O(n)$。每个元素只转移 3 个余数状态。
- 空间复杂度:$O(1)$。
dp和next的长度固定为 3。
关键点总结
[!green]
- 状态只保留余数与该余数下的最大和,把指数级子集压缩为 3 个槽位。
- 同余状态中较大的和支配较小的和,这是状态可以合并的依据。
- 快照不是写法偏好,而是保证「每个元素最多选一次」的 0-1 约束。
- 空集使
dp[0]从0开始,因此答案始终存在。
易错点总结
[!yellow]
- 直接原地更新
dp:本轮产生的状态可能再次加入同一个num,相当于重复使用元素。- 不跳过
-1状态:不存在的子集会参与转移,产生虚假的候选和。- 只记录是否可达:题目要求最大和,同一余数必须保留数值最大的状态。
- 返回三个状态中的最大值:最大值的余数未必是
0,最终只能返回dp[0]。- 误用连续子数组方法:本题选择的是任意子集,元素位置没有连续性约束。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 1363. 形成三的最大倍数 | 困难 | 同样按模3分类并舍弃损失最小的元素,原题最大化拼成的整数,本题最大化元素和。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!