ArrayList移除重复超N次元素代码Bug求助(N=1时漏删元素)
问题分析与修复方案
首先,咱们来拆解一下你的代码为什么会在maxOccurrences=1且列表较长时出现遗漏元素的情况,主要有两个核心问题:
1. 元素移除后的索引偏移bug
当你执行test.remove(j)时,ArrayList中j位置之后的所有元素都会向前移动一位,但你的内层循环j会继续自增(j++),这就导致你跳过了原本在j+1位置、现在移到j位置的元素。举个例子:
- 假设列表是
[A, A, A],i=0,temp=A j=1时,发现重复,counter=1,满足>=1,移除j=1的元素,列表变成[A, A]- 然后
j++变成2,此时j >= test.size()(size是2),内层循环结束,剩下的那个A就没被处理到
这种索引偏移在列表较长时,会随机导致某个重复元素被跳过,尤其是当多个重复元素连续出现时。
2. isSorted的逻辑错误
你的代码中,只要当前i对应的counter < maxOccurrences,就把isSorted设为true,但这会覆盖之前可能设为false的状态。比如:
- 列表前几个元素没有重复,
isSorted被设为true - 但后面的元素存在重复,此时
isSorted已经是true,外层while循环直接退出,导致那些重复元素没被处理完
这就是为什么重复执行一次代码块就能删除遗漏元素——第二次执行时,剩下的重复元素被遍历到了。
修复后的代码
针对这两个问题,我们可以调整代码逻辑:
boolean hasDuplicates; do { hasDuplicates = false; // 从后往前遍历,避免移除元素后的索引偏移问题 for (int i = test.size() - 1; i >= 0; i--) { int counter = 0; Object temp = test.get(i); // 向前查找重复元素 for (int j = i - 1; j >= 0; j--) { if (temp.equals(test.get(j))) { // 注意:如果是引用类型,建议用equals而不是== counter++; if (counter >= maxOccurrences) { test.remove(i); hasDuplicates = true; break; // 已经移除当前元素,无需继续计数 } } } } } while (hasDuplicates);
关键优化点:
- 从后往前遍历:移除元素时,不会影响前面未遍历的元素索引,彻底避免了偏移问题
- 修正循环终止条件:用
hasDuplicates标记是否还有需要处理的重复元素,只要处理过一次移除,就继续循环,直到没有重复需要处理 - 替换
==为equals:如果你的列表中存的是引用类型(比如自定义对象),==比较的是内存地址,应该用equals来判断内容相等(如果是基本类型包装类,==在某些场景也能工作,但equals更稳妥)
如果你坚持想用原来的从前往后遍历的方式,也可以在移除元素后手动调整j的值:
boolean hasDuplicates; do { hasDuplicates = false; for (int i = 0; i < test.size(); i++) { int counter = 0; Object temp = test.get(i); for (int j = i + 1; j < test.size(); j++) { if (temp.equals(test.get(j))) { counter++; if (counter >= maxOccurrences) { test.remove(j); hasDuplicates = true; j--; // 移除元素后,j回退一位,避免跳过下一个元素 } } } } } while (hasDuplicates);
这样也能解决索引偏移的问题,同时修正了循环终止条件,确保所有重复元素都被处理。
内容的提问来源于stack exchange,提问作者eldlit
相关产品推荐
相关产品推荐

