
本文详解一个经典 arraylist 操作问题:循环提取当前列表最小值,累加至总和后移除该最小值及其左右相邻元素(边界特殊处理),直至列表为空或不足操作条件;重点修复原代码因未同步更新长度导致的无限循环缺陷,并提供健壮、可读性强的实现方案。
本文详解一个经典 arraylist 操作问题:循环提取当前列表最小值,累加至总和后移除该最小值及其左右相邻元素(边界特殊处理),直至列表为空或不足操作条件;重点修复原代码因未同步更新长度导致的无限循环缺陷,并提供健壮、可读性强的实现方案。
该问题看似简单,实则暗藏两个关键陷阱:逻辑边界错误与状态不同步。原始代码中,变量 l 初始设为列表长度,但后续在 while 循环内执行 remove() 操作时,仅在部分分支中更新了 l(如 l -= 2 或 l--),却遗漏了 index != 0 && l == 2 等边界情形——更严重的是,所有 remove() 调用均未考虑 ArrayList 动态缩容后索引偏移问题,导致 index+1 或 index-1 可能越界或指向错误元素。
例如,当 ques = [8,4,9,10,34,54,56] 时,首次最小值 4 位于索引 1。按题意应移除 [8,4,9](即索引 0,1,2)。但若先执行 ques.remove(index-1)(删索引 0 → 8),列表变为 [4,9,10,34,54,56],此时原索引 1 处的 4 已移至索引 0,继续 remove(index)(即删索引 1)将误删 9,而非 4——这是典型的索引失效问题。
✅ 正确解法必须遵循「先定位、再批量移除、最后同步更新长度」原则。推荐采用逆序删除索引(从大到小)避免偏移,或更清晰的做法:收集待删索引集,排序后倒序移除。以下是优化后的工业级实现:
import java.util.*;
public class MinAdjacentRemoval {
public static void main(String[] args) {
List<integer> ques = new ArrayList(Arrays.asList(8, 4, 9, 10, 34, 54, 56));
int sum = 0;
while (!ques.isEmpty()) {
// 步骤1:找最小值及其索引
int min = Collections.min(ques);
int index = ques.indexOf(min);
sum += min;
// 步骤2:确定待删除的索引集合(含边界保护)
Set<integer> indicesToRemove = new TreeSet(Collections.reverseOrder());
if (index > 0) indicesToRemove.add(index - 1); // 左邻
indicesToRemove.add(index); // 自身
if (index <p>? <strong>关键改进说明</strong>: </p>
<ul>
<li>✅ 使用 <code>TreeSet</code>(降序)自动去重并逆序遍历,彻底规避 <code>remove()</code> 引起的索引漂移; </li>
<li>✅ 边界判断明确:<code>index > 0</code> 才加左邻,<code>index 才加右邻; </code>
</li>
<li>✅ 删除前二次校验 <code>i ,防御性编程; </code>
</li>
<li>✅ 移除 <code>l</code> 变量,直接用 <code>!ques.isEmpty()</code> 控制循环,语义更清晰、不易出错。</li>
</ul>
<p>⚠️ <strong>注意事项</strong>: </p>
<ul>
<li>
<code>Collections.min()</code> 和 <code>indexOf()</code> 时间复杂度均为 <em>O(n)</em>,整体算法为 <em>O(n²)</em>;若数据量极大(如 >10⁵),建议改用优先队列(<code>PriorityQueue</code>)维护最小值索引,并辅以布尔标记数组实现 <em>O(n log n)</em> 解法; </li>
<li>原始代码中 <code>else if (index != 0 && l > 2)</code> 分支未覆盖 <code>l == 1</code> 或 <code>l == 2</code> 且 <code>index != 0</code> 的情况(如 <code>[5,2]</code>),会导致跳过删除逻辑,使循环卡死——本方案通过 <code>isEmpty()</code> 条件根治此缺陷。</li>
</ul>
<p>最终输出 <code>sum = 68</code>(4 + 10 + 54),完全符合题目要求。掌握这种「索引安全删除」模式,可复用于各类动态列表的局部清理场景。</p></integer></integer>










