leetcode 452 用最少数量的箭引爆气球 贪心算法

一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球

题解:先排序,然后遍历检查是否满足合并区间的条件,判断是否有交叉区间,计算已知区间的交集数量。

排序后结果:【【1,6】,【2,8】,【7,12】,【10,16】】

1.待发射箭头的区间range=【1,6】,需要的箭的数量arrow=1;

2.区间【2,8】和待发射区间【1,6】有交集,更新发射区域为它们的交集range为【2,6】

3.区间【7,12】和待发射区间【2,6】没有任何交集,说明需要增加一个新的发射区域,新的发射区域range=【7,12】

4.区间【10,16】和待发射区域【7,12】有交集,待发射区域更新为【10,12】

代码如下:

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        // 对于empty或只有一个区间, return;
        if (points.size() <= 1)
            return points.size();
        // 按照区间开始位置排序
        sort(points.begin(), points.end(),
            [](const vector<int> &a, const vector<int> b) {
                return a[0] == b[0] ? a[1] <= b[1] : a[0] < b[0];
            });

        int arrows = 1;
        // 初始化待发射区为[points[0][0], points[0][1]] ;
        vector<int> range = {points[0][0], points[0][1]};
        for (int i = 1; i < points.size(); i++) {
            auto curr = points[i];
            // 当前区间和待发射区间有交集, 更新交叉区间
            if (curr[0] <= range[1]) {
                range[0] = max(range[0], curr[0]);
                range[1] = min(range[1], curr[1]);
            } else {
                // 没有交集, 增加箭头数量, 将待发射区间设置为当前区间
                ++arrows;
                range[0] = curr[0];
                range[1] = curr[1];
            }
        }
        return arrows;
    }
};

第二种思路:

用区间的尾部排序效率更高,因为已经保证后面区间的区间右侧都是大于当前区间的,所以将发射点设置在右侧边界,当后面的区间左边界比它更靠左时,则可以一起被处理掉。

这里换个example: [[10,16],[2,5],[1,6],[7,12]] 为例子:

先排序, 按区间结束位置排序, 排序后: [[2,5],[1, 6],[7,12],[10,16]]
遍历计算交叉区间,
1.发射点初始化为pos = 5, 需要的箭数量 arrows = 1;
2.区间[1, 6], 1 是小于5的, 在点5射箭可以干掉这个区间
3.区间[7, 12], 在5的位置射箭无法打掉, 说明需要增加一个新的发射点, 新的待发射点pos = 12
4.区间[10,16], 10 < 12那么在12位置射箭可以干掉它

代码如下:

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.size() <= 1) {
            return points.size();
        }
        sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[1] < b[1];
        });

        // 发射点设置为区间最右侧的点
        int pos = points[0][1];
        int arrows = 1;
        for (int i = 1; i < points.size(); i++) {
            auto curr = points[i];
            if (curr[0] > pos) {
                pos = curr[1];
                ++arrows;
            }
        }

        return arrows;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值