《代码随想录》Ⅷ 贪心算法 452. 用最少数量的箭引爆气球

《代码随想录》Ⅷ 贪心算法 452. 用最少数量的箭引爆气球

革命尚未成功,同志仍需努力!

题目:力扣链接

  • 我们有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points​ 中,其中 points[i] = [xstart, xend]​ 表示第 i 个气球的水平直径在 xstart​ 和 xend​ 之间。我们不知道气球的确切 y 坐标。

    一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,如果一个气球的直径的开始和结束坐标为 xstart​ 和 xend​,且满足 xstart ≤ x ≤ xend​,则该气球会被引爆。可以射出的弓箭的数量没有限制。弓箭一旦被射出之后,可以无限地前进。

    给定一个数组 points​,返回引爆所有气球所必须射出的最小弓箭数。

一、思想

这道题的核心思想是使用贪心算法。具体来说:

  1. 区间重叠问题:将每个气球看作一个区间,问题转化为找到最少的点,使得每个区间至少包含一个点

  2. 排序策略:首先将所有区间按照起始点进行排序

  3. 合并重叠区间:遍历排序后的区间,维护当前箭能覆盖的最大范围:

    • 如果新区间与当前范围有重叠,则更新范围右边界为两者较小值
    • 如果没有重叠,则需要新增一支箭,并更新范围右边界

这种方法的正确性在于:

  • 排序后可以保证每次处理都是最左的未覆盖区间
  • 取最小右边界可以最大化后续区间的覆盖可能性

二、代码

class Solution
{
public:
    /**
     * 比较函数,用于比较两个目标点,按照第一个元素的大小进行排序。
     * @param a 目标点a
     * @param b 目标点b
     * @return 如果a的第一个元素小于b的第一个元素,返回true,否则返回false
     */
    static bool cmp(const vector<int> &a, const vector<int> &b) { return a[0] < b[0]; }
    /**
     * 找出最少需要的箭的数量,使得箭矢能够穿过所有的目标点。
     * @param points 目标点集合,每个目标点是一个包含两个元素的数组,分别表示目标点的左右边界
     * @return 最少需要的箭的数量
     */
    int findMinArrowShots(vector<vector<int>> &points)
    {
        // 如果目标点集合为空,则不需要任何箭,返回0
        if (points.size() == 0) {
            return 0;
        }

        // 初始化箭的数量为1
        int res = 1;
        // 对目标点集合按照第一个元素进行排序
        sort(points.begin(), points.end(), cmp);
        // 初始化右边界为第一个目标点的右边界
        int right = points[0][1];
        // 遍历目标点集合
        for (int i = 1; i < points.size(); ++i) {
            // 如果当前目标点的左边界大于右边界,则需要增加箭的数量,并更新右边界
            if (points[i][0] > right) {
                res++;
                right = points[i][1];
            }
            // 如果当前目标点的左边界不大于右边界,则更新右边界为当前目标点和右边界中的较小值
            else {
                right = min(right, points[i][1]);
            }
        }

        // 返回箭的数量
        return res;
    }
};

三、代码解析

1. 算法工作原理分解
1.1 排序阶段
  • 目的:将所有气球区间按照左端点升序排列
  • 关键点:确保处理区间时从左到右顺序进行
  • 比较函数cmp​函数定义按xstart​升序排列
1.2 初始化
  • res=1:至少需要一支箭
  • right:初始化第一支箭的有效覆盖右边界
1.3 遍历处理
  • 无重叠情况xstart > right​):

    • 需要新增一支箭
    • 更新右边界为新区间的右端点
  • 有重叠情况

    • 不增加箭数
    • 收缩右边界为两者较小值(关键贪心策略)
2. 关键点说明
2.1 贪心选择证明
  • 每次选择最小右边界可以保证:

    • 当前箭覆盖最多后续区间
    • 不会遗漏任何必须单独处理的区间
2.2 边界情况处理
  • 空输入直接返回0
  • 单气球情况返回1
2.3 时间复杂度优化
  • 排序使后续处理只需线性扫描
  • 维护右边界避免重复计算

四、复杂度分析

  • 时间复杂度O(n log n)

    • 排序阶段:O(n log n)​(使用标准库的快速排序)
    • 遍历处理阶段:O(n)​(单次线性扫描)
  • 空间复杂度O(1)

    • 仅使用固定数量的额外变量(res, right等)
    • 排序操作可能使用O(log n)​的递归栈空间(取决于具体实现)

白展堂:人生就是这样,苦和累你总得选一样吧?哪有什么好事都让你一个人占了呢。 ——《武林外传》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值