
本文详解一个常见但易出错的 arraylist 操作逻辑:循环查找最小值、累加求和,并移除该最小值及其相邻元素;重点修复原代码因未同步更新列表长度导致的无限循环问题,并提供健壮、可读性强的优化实现。
本文详解一个常见但易出错的 arraylist 操作逻辑:循环查找最小值、累加求和,并移除该最小值及其相邻元素;重点修复原代码因未同步更新列表长度导致的无限循环问题,并提供健壮、可读性强的优化实现。
在处理动态列表操作时,一个典型误区是:仅修改集合内容,却忽略对控制循环的边界变量(如 l)进行同步更新。原代码中虽然在每个 if-else 分支里调用了 remove(),但部分分支遗漏了 l 的递减操作(例如 index == 0 && l == 2 分支中只执行 l--,而 index != 0 && l > 2 分支虽有 l -= 3,但若 l == 1 或 l == 2 时进入该分支则会越界),更严重的是——当列表最终只剩 1 个元素时,index != 0 条件不成立,且无对应 else 处理,导致 l 停滞不前,陷入死循环。
以下是修正并增强后的完整实现,兼顾正确性、边界鲁棒性和可维护性:
import java.util.*;
public class MinRemovalSum {
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:确定待删除的索引范围(左邻、自身、右邻)
int left = Math.max(0, index - 1);
int right = Math.min(ques.size() - 1, index + 1);
// 步骤3:从右向左删除(避免索引偏移)
for (int i = right; i >= left; i--) {
ques.remove(i);
}
}
System.out.println("sum = " + sum); // 输出:sum = 68
}
}✅ 关键优化点说明:
-
不再依赖外部长度变量
l:直接用!ques.isEmpty()控制循环,彻底规避长度不同步风险; -
统一删除逻辑:无论最小值位于开头、中间或末尾,均计算安全的
[left, right]区间,并逆序删除(从高索引到低索引),防止因前面元素移除导致后续索引失效; -
边界自动防护:
Math.max(0, index-1)和Math.min(size-1, index+1)确保不越界,无需冗余if-else判断; - 语义清晰:每步操作职责单一,便于理解和单元测试。
⚠️ 注意事项:
-
Collections.min()和indexOf()时间复杂度均为 O(n),整体算法为 O(n²),适用于中小规模数据;若需极致性能(如百万级元素),建议改用优先队列 + 索引标记的延迟删除策略; -
ArrayList.remove(int index)是 O(n) 操作,频繁删除时可考虑切换为LinkedList(但随机访问变慢),权衡需依实际场景而定; - 实际工程中建议将核心逻辑封装为独立方法(如
removeMinAndNeighbors(List<integer>)</integer>),提升复用性与可测性。
通过以上重构,代码不仅修复了原始死循环缺陷,更具备了生产环境所需的健壮性与可演进性。

















