SWE / PE · Coding

Meta 最少箭射气球:闭区间端点贪心

对闭区间气球选择最少射击位置,使用最早结束点覆盖,并处理相接端点。

题目重点:对闭区间气球选择最少射击位置,使用最早结束点覆盖,并处理相接端点。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 每气球为闭区间[left,right],left≤right;一箭任意实数x,覆盖所有包含x的区间。输入不修改,空列表0。
  • 与半开区间会议调度不同,left等于已有射点时仍被覆盖。

解题路线

  1. 按right升序,遇第一个尚未被覆盖区间时,在其right射箭;随后所有left≤该射点的区间都覆盖,不需要更新已有射点。
  2. 交换证明:任何方案为最早结束区间射的某箭x≤right,把它移到right,不会失去对尚未处理区间的覆盖,因为其他区间right≥该right且若原包含x,它们left≤x≤right。因此最右允许点至少同样好。
  3. 区间left>currentArrow才新开箭;相等不新开。多个相同right自然一箭,点区间[left=right]合法。
  4. 排序是主要成本;不要按left分组后只延长当前right,那容易把交集变并集,错误认为一箭覆盖没有公共点的链。

手动走一遍

[1,2]、[2,3]一箭x2覆盖两者;[1,2]、[3,4]需2箭。[1,3]、[2,4]、[4,5]前两可x3,第三需新箭,不能因为区间链连通就判1。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

def minimum_arrows(intervals):
    """Closed intervals, arbitrary real coordinate arrows; input unmodified."""
    if any(a>b for a,b in intervals):raise ValueError('reversed interval')
    end=None;arrows=0
    for left,right in sorted(intervals,key=lambda p:p[1]):
        if end is None or left>end:
            end=right;arrows+=1
    return arrows

复杂度

O(N log N)排序、O(N)扫描;本实现sorted新建O(N)辅助空间,若输入可原地排序,另计排序算法辅助空间。整数端点的测试可穷举所有端点射击子集做独立最优对照。

易错点与追问

容易失分的边界

  • 用left≥arrow判新箭会把相接闭区间误判。
  • 连通并集不代表所有区间有共同交点。

继续深挖

  • 若射击位置只能取某个候选集合,最早结束区间的右端未必可选,应怎样选可行点?
  • 每箭有不同成本时,贪心最少数量还能保证最小成本吗?
✓已复制微信号!