使用Java从数值列表提取交替顺序局部最大值和最小值的算法求助
现有代码问题
- 首点判定逻辑不合理:直接将第一个点与第二个点的比较结果作为首点的极值类型并加入结果,没有考虑后续走势,大概率会出现开头连续同类型极值,破坏交替规则。
- 过滤时机错误:提前用差值阈值过滤还未确认是否为极值的点,会漏过很多符合差值要求的真实极值。
- 缺少交替校验逻辑:没有处理连续出现的同类型极值,会直接打破「最小、最大、最小」的交替要求。
- 差值百分比计算有缺陷:直接以上一个极值作为分母,若上一个极值数值接近0会触发除零异常,且低数值区间的微小波动也容易误触发阈值。
正确实现思路
步骤1:先全量提取所有符合定义的局部极值
遍历除首尾点外的所有点位,用你现有的isMaximum、isMinimum方法判定是否为局部极值,给符合条件的点标记类型后存入原始极值列表,此阶段不做任何差值过滤。
首尾点可根据业务需求决定是否保留,建议最终过滤完成后再判断是否补充到结果首尾,不要提前加入极值列表。
步骤2:对原始极值列表做交替校验+差值过滤
- 初始化结果列表,先将原始极值列表的第一个元素加入结果,记录上一个已加入极值的类型与数值。
- 从第二个元素开始遍历原始极值列表:
- 若当前极值类型和上一个已加入极值的类型相同:保留更极端的那个,比如连续两个最大值就留数值更大的,替换结果列表的最后一个元素;连续两个最小值就留数值更小的替换。
- 若当前极值类型和上一个已加入极值的类型相反:计算两点的差值百分比,差值超过阈值则将当前极值加入结果列表,更新上一个极值的记录;未超过阈值则直接跳过当前极值。
优化差值计算逻辑
修改isTrueExtremum方法,取两个数的最大值作为分母,避免除零风险和低数值误判:
public boolean isTrueExtremum(double previous, double current , double percentage) { double diff = Math.abs(current - previous); double base = Math.max(Math.abs(previous), Math.abs(current)); // 避免两个数都接近0时的除零问题 if (base < 1e-9) { return false; } double diffPercentage = diff / base; return diffPercentage > percentage; }
优化后核心代码示例
public List<Track> extremumsFinder(double percentage) throws ParseException { List<Track> rawExtremums = new ArrayList<>(); // 第一步:先提取所有原始局部极值 for (int i = 1; i < tracks.size() - 1; i++) { double prev = tracks.get(i-1).getVolume(); double curr = tracks.get(i).getVolume(); double next = tracks.get(i+1).getVolume(); if (isMaximum(prev, curr, next)) { tracks.get(i).setType(TrackType.max); rawExtremums.add(tracks.get(i)); } else if (isMinimum(prev, curr, next)) { tracks.get(i).setType(TrackType.min); rawExtremums.add(tracks.get(i)); } } if (rawExtremums.isEmpty()) { return rawExtremums; } // 第二步:过滤+保证交替顺序 List<Track> result = new ArrayList<>(); Track lastExtremum = rawExtremums.get(0); result.add(lastExtremum); for (int i = 1; i < rawExtremums.size(); i++) { Track curr = rawExtremums.get(i); // 同类型极值,留更极端的 if (curr.getType() == lastExtremum.getType()) { if ((curr.getType() == TrackType.max && curr.getVolume() > lastExtremum.getVolume()) || (curr.getType() == TrackType.min && curr.getVolume() < lastExtremum.getVolume())) { result.remove(result.size() - 1); result.add(curr); lastExtremum = curr; } } else { // 不同类型,判断差值是否符合要求 if (isTrueExtremum(lastExtremum.getVolume(), curr.getVolume(), percentage)) { result.add(curr); lastExtremum = curr; } } } // 可选:如果需要保留首尾点,可在这里补充判定逻辑 return result; }
内容的提问来源于stack exchange,提问作者Mons
相关产品推荐
相关产品推荐

