
本文讲解如何通过贪心策略结合最大堆(优先队列)求解“最小滤网数使总污染减半”问题,核心是每次选择当前污染最高的工厂安装滤网,从而以最少操作达成目标。
本文讲解如何通过贪心策略结合最大堆(优先队列)求解“最小滤网数使总污染减半”问题,核心是每次选择当前污染最高的工厂安装滤网,从而以最少操作达成目标。
在环保优化类面试题中,常出现一类典型的贪心+数据结构问题:给定 N 个工厂的初始污染值,每安装一个滤网可将某工厂当前污染值减半(即乘以 0.5),允许多次在同一个工厂安装滤网。目标是使所有工厂污染总和 ≤ 初始总和的一半,并求所需滤网的最小数量。
该问题的关键洞察在于:每次应优先处理当前污染值最高的工厂——因为减半操作带来的绝对削减量(即 current_value / 2)在此处最大,从而以最少步骤逼近目标。若采用简单排序后依次处理(如原错误尝试中仅遍历一次),无法动态反映“处理后该工厂污染下降、但可能仍为新最大值”的事实,因此必须支持动态获取并更新最大值,这正是最大堆(PriorityQueue 配合 Collections.reverseOrder())的典型应用场景。
以下是完整、高效的 Java 实现:
import java.util.*;
public static int getMinimumFilters(double[] pollutionLevels) {
double currentPollution = Arrays.stream(pollutionLevels).sum();
double targetPollution = currentPollution / 2.0;
// 构建最大堆:优先队列按降序排列
PriorityQueue<Double> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
for (double level : pollutionLevels) {
maxHeap.offer(level);
}
int numFilters = 0;
// 贪心循环:只要总污染仍高于目标,就对当前最严重工厂安装滤网
while (currentPollution > targetPollution) {
double maxPollution = maxHeap.poll(); // 取出当前最高污染值
double reduced = maxPollution / 2.0; // 安装滤网后的新值
maxHeap.offer(reduced); // 将减半后的值重新入堆
currentPollution -= reduced; // 总污染减少量 = 原值 - 新值 = maxPollution/2
numFilters++;
}
return numFilters;
}✅ 算法正确性说明:
- 每次操作都选取当前最大污染值进行减半,保证单步削减量最大化;
- 堆结构确保 O(log N) 时间内完成取最大值与插入新值,整体时间复杂度为 O(K log N),其中 K 为实际滤网数(远小于 N,在最坏情况下 K ≈ log₂(max_value) × N,但实践中收敛极快);
- 空间复杂度为 O(N),用于维护堆。
⚠️ 注意事项:
- 使用 double 类型处理减半运算,避免整数除法导致精度丢失(如 18/2=9 正确,但 9/2=4 在整型下会截断为 4,而实际需 4.5);
- 不要预先排序后静态遍历——工厂污染值动态变化,必须持续追踪实时最大值;
- 边界情况(如全零数组)会直接跳过 while 循环,返回 0,逻辑自然兼容。
该解法简洁、高效、符合工程实践,是面试中展示数据结构理解与贪心思想应用的典范答案。

















