在问 · 算法题解

452. 用最少数量的箭引爆气球

题目描述

墙上贴着若干气球。points[i] = [x_start, x_end] 表示第 i 个气球在水平方向上覆盖的范围,它的竖直位置未知。

可以在任意横坐标 x 处竖直向上射箭,箭会一直飞下去,凡满足 x_start <= x <= x_end 的气球都会被射破。箭的数量不限。

返回让所有气球都破掉所需的最少箭数。

示例 1
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2

解释:在 x = 6 射一箭破 [2,8] 和 [1,6],在 x = 11 射一箭破 [10,16] 和 [7,12]。

示例 2
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4

解释:四个气球互不相交,每个都要单独一箭。

示例 3
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2

解释:在 x = 2 和 x = 4 各射一箭即可,端点相同也能同时射破。

数据范围

  • 1 <= points.length <= 10^5
  • points[i].length == 2
  • -2^31 <= x_start < x_end <= 2^31 - 1

解题思路

按右端点从小到大排序。第一支箭射在第一个气球的右端点 end:这是能射中它的最靠右位置,能顺带射中尽可能多的后续气球。依次检查后面的气球:起点 a ≤ end 说明已经被这支箭射中;a > end 说明射不到,需要新箭,射在这个气球的右端点。

为什么正确

end 是当前这支箭的位置,所有右端点不超过 end 的气球都已被某支箭射中,且已用的箭数是最少的。

复杂度分析

时间 O(n log n),空间 O(log n)(排序栈)。

易错点

区间是闭区间,起点等于 end 时也能射中,所以判断条件是 a > end 而不是 a >= end。比较器不要写 x[1] - y[1],坐标可达 ±2^31,相减会溢出。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        points.sort(key=lambda p: p[1])
        arrows = 1
        end = points[0][1]
        for a, b in points[1:]:
            if a > end:
                arrows += 1
                end = b
        return arrows

载入编辑器,自己跑一遍 →

贪心 专题的其他题目

查看 贪心 全部题目 →