本文详解如何在双篮子约束下(相邻相同元素自动消失)最大化保留元素总数,指出常见贪心误判点,并提供可验证的正确实现逻辑与代码。
本文详解如何在双篮子约束下(相邻相同元素自动消失)最大化保留元素总数,指出常见贪心误判点,并提供可验证的正确实现逻辑与代码。
在该问题中,我们面对一个关键机制:每个篮子内部若出现两个连续相等的元素,后插入的那个会“自动消失”——注意,这不是简单的“禁止插入”,而是“允许插入但立即触发删除”。许多解法(包括题中提供的代码)错误地将此理解为“避免向已有相同尾元素的篮子添加”,从而退化为静态判断,忽略了“插入→触发消失→实际未增加长度”这一动态过程。更严重的是,原代码甚至未模拟消失行为本身,导致篮子大小被高估。
核心误区剖析
原实现存在两处根本性错误:
- 未建模“消失”动作:basket1.add(num) 后若 num == basket1.get(basket1.size()-2)(即新元素与倒数第二个相同,而倒数第一个刚被它触发消失),实际篮子长度不变,但代码仍计为+1;
- 决策逻辑不完整:仅当 basket1 尾部不匹配时才选 basket1,否则尝试 basket2;但若 basket2 尾部也匹配,代码直接跳过插入——这相当于“丢弃该元素”,而题目要求必须放入某一篮子(再触发消失)。因此,任何元素都必须被尝试插入,且插入后需立即检查并执行删除。
正确建模:插入 + 即时清理
每个篮子应视为支持“末位比较→插入→检测相邻重复→必要时移除末位”的序列。由于只影响末两位,我们只需维护篮子末尾元素及长度,无需存储全部历史(但为清晰演示,以下用 ArrayList 并显式 remove()):
public static int maxBasketSum(int[] A) {
List<Integer> basket1 = new ArrayList<>();
List<Integer> basket2 = new ArrayList<>();
for (int num : A) {
// 尝试放入 basket1:插入后检查是否造成相邻重复
boolean inserted1 = false;
if (basket1.isEmpty() || basket1.get(basket1.size() - 1) != num) {
basket1.add(num);
inserted1 = true;
} else {
// 尾部相同 → 插入后形成 [..., x, x] → 删除最后一个 x
basket1.add(num); // 先插入
basket1.remove(basket1.size() - 1); // 立即移除,长度不变
}
// 若 basket1 未成功“净增加”,再尝试 basket2
if (!inserted1) {
if (basket2.isEmpty() || basket2.get(basket2.size() - 1) != num) {
basket2.add(num);
} else {
basket2.add(num);
basket2.remove(basket2.size() - 1);
}
}
}
return basket1.size() + basket2.size();
}✅ 关键修正:每次插入都执行,然后立即按规则清理。不存在“跳过插入”,只有“插入后清零”。
更优实现:空间优化版
因只需末尾元素和长度,可用两个变量替代列表:
public static int maxBasketSumOptimized(int[] A) {
int size1 = 0, size2 = 0;
Integer tail1 = null, tail2 = null; // 记录各篮子当前尾元素
for (int num : A) {
// 优先尝试 basket1
if (tail1 == null || !tail1.equals(num)) {
tail1 = num;
size1++;
} else {
// 插入后立即消失:tail1 不变,size1 不增
// (等价于:不更新 tail1,size1 不变)
}
// 若 basket1 未净增加,则强制放入 basket2
if (tail1 != null && tail1.equals(num)) {
if (tail2 == null || !tail2.equals(num)) {
tail2 = num;
size2++;
}
// 否则 basket2 也消失:size2 不变,tail2 不变
}
}
return size1 + size2;
}注意事项与验证要点
- 必须覆盖所有分支:对每个 num,它必然被插入某篮子(即使随后消失),不可遗漏;
- “消失”仅作用于最末端一对:如 basket = [1,2,2],再加 2 → 变为 [1,2,2,2] → 仅末两位 2,2 触发消失 → 结果为 [1,2](不是清空全部重复);
-
测试用例建议:
A = [1,1,1] → 输出 2(如:b1=[1], b2=[1,1]→[1] → sum=2);
A = [1,2,1,2] → 输出 4(无相邻重复,全保留)。
掌握“插入即清理”的状态机思维,是解决此类隐式规则题目的核心。勿预判,而要忠实模拟每一步物理行为。










