如何不使用Set接口移除列表重复元素?求移除指定元素1的更优方案
移除列表特定元素与无Set去重方案
一、移除列表中的数字1:修正你的现有方案
你当前使用的list.removeIf(el->Collections.frequency(list, el)>1);存在两个问题:
- 逻辑偏差:这个条件会移除所有出现次数大于1的元素,而非仅移除数字1。比如列表若为
[1,2,1,3,3],执行后会同时删掉1和3,剩下[2],不符合需求。 - 效率低下:
Collections.frequency()每次都会遍历整个列表,时间复杂度为O(n²),数据量大时性能很差。
最优写法
直接判断元素是否为1即可,时间复杂度O(n),简洁高效:
list.removeIf(el -> el.equals(1));
(如果确定元素在Integer缓存范围内[-128,127],用el == 1也可以,但equals更稳妥)
二、不使用Set接口移除重复元素的方案
根据是否需要保留元素原始顺序,有以下几种可行方案:
1. 保留原始顺序:临时列表记录+反向遍历
反向遍历可避免移除元素导致的索引偏移问题,逻辑清晰:
ArrayList<Integer> seen = new ArrayList<>(); // 从后往前遍历,避免移除元素后索引错乱 for (int i = list.size() - 1; i >= 0; i--) { Integer num = list.get(i); if (seen.contains(num)) { list.remove(i); } else { seen.add(num); } }
时间复杂度O(n²),适合中小规模列表。
2. 保留原始顺序:Stream自定义过滤
用Stream结合内部状态容器实现过滤,代码更简洁:
ArrayList<Integer> uniqueList = list.stream() .filter(new Predicate<Integer>() { private final ArrayList<Integer> seen = new ArrayList<>(); @Override public boolean test(Integer num) { boolean notSeen = !seen.contains(num); if (notSeen) seen.add(num); return notSeen; } }) .collect(Collectors.toCollection(ArrayList::new));
本质和方案1逻辑一致,时间复杂度同样为O(n²)。
3. 不要求原始顺序:排序后移除相邻重复项
如果可以接受元素顺序改变,排序后移除相邻重复项的性能最优,时间复杂度由排序决定为O(n log n):
Collections.sort(list); int i = 1; while (i < list.size()) { if (list.get(i).equals(list.get(i-1))) { list.remove(i); } else { i++; } }
内容的提问来源于stack exchange,提问作者Dhaivat Joshi
相关产品推荐
相关产品推荐

