Java构建最大堆时Collections.reverseOrder与(b-a)比较器结果差异问题
两种最大堆实现的差异原理说明
核心原因是自定义减法比较器存在整数溢出风险,两种写法的底层逻辑并不完全等价:
new PriorityQueue<>(Collections.reverseOrder())的实现逻辑:
该方法返回的比较器底层调用Integer.compareTo()完成大小对比,仅做值的大小判断,不涉及减法运算,不存在溢出风险,排序逻辑始终正确。new PriorityQueue<>((a, b) -> b - a)的实现逻辑:
自定义比较器通过减法计算返回值,当两个int值的差值超出int的取值范围(-2^31 ~ 2^31 - 1)时,会发生整数溢出,导致比较结果和实际大小关系完全相反。
举个典型的溢出场景:当b = 2147483647(int最大值)、a = -2147483648(int最小值)时,b - a的理论值为4294967295,溢出后会被截断为int类型的-1,比较器返回负数会判定b < a,和实际的b > a完全相反,直接破坏堆的排序结构。- 本题触发问题的原因:
LeetCode 480的用例中nums元素覆盖了int的全量取值范围,当滑动窗口中同时出现极大值和极小值时,减法比较器就会触发溢出,导致堆的结构异常,最终计算的中位数不符合预期,提交失败。 - 等价安全的自定义比较器写法:
如果你不想用Collections.reverseOrder(),可以改为(a, b) -> Integer.compare(b, a),该写法和Collections.reverseOrder()逻辑完全一致,也不会存在溢出风险。
内容的提问来源于stack exchange,提问作者Gloria1009
相关产品推荐
相关产品推荐

