Files
leetcode-master/problems/0452.用最少数量的箭引爆气球.md
youngyangyang04 e08fd0eea7 Update
2020-11-24 08:37:52 +08:00

3.9 KiB
Raw Blame History

思路

接下来在想一下如何使用最少的弓箭。

直觉上来看,貌似只射重叠最多的气球,用的弓箭一定最少,那么有没有当前重叠了三个,我射两个,留下一个和后面的一起射这样弓箭用的更少的情况呢?

尝试一下举反例,发现没有这种情况,那么就试一试贪心吧!

算法确定下来了,那么如何模拟气球涉爆的过程呢?是在数组中移除元素还是做标记呢?

如果真实的模拟射气球的过程应该射一个气球数组就remove一个元素这样最直观毕竟气球被射了。

但又想一下如果把气球排序之后从前到后遍历气球被射过的气球仅仅跳过就行了没有必要让气球数组remove气球记录一下箭的数量就可以了。

PS:本文leetcode刷题攻略已收录,更多精彩算法文章尽在公众号:代码随想录,关注后就会发现和「代码随想录」相见恨晚!

以上为思考过程,已经确定下来使用贪心了,那么开始解题。

为了让气球尽可能的重叠,需要对数组进行排序

那么按照气球起始位置排序,还是按照气球终止位置排序呢?

其实都可以!只不过对应的遍历顺序不同,我就按照气球的起始位置排序了。

既然按照其实位置排序,那么就从前向后遍历气球数组,靠左尽可能让气球重复。

从前向后遍历遇到重叠的气球了怎么办?

如果气球重叠了,重叠气球中右边边界的最小值 之前的区间一定需要一个弓箭。

以题目示例: 10,16],[2,8],[1,6],[7,12为例,如图:(方便起见,已经排序)

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

可以看出首先第一组重叠气球一定是需要一个箭气球3的左边界大于了 第一组重叠气球的最小右边界所以再需要一支箭来射气球3了。

C++代码如下:

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

        int result = 1; // points 不为空至少需要一支箭
        for (int i = 1; i < points.size(); i++) {
            if (points[i][0] > points[i - 1][1]) {  // 气球i和气球i-1不挨着注意这里不是>=
                result++; // 需要一支箭
            }
            else {  // 气球i和气球i-1挨着
                points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界
            }
        }
        return result;
    }
};

时间复杂度O(nlogn)
空间复杂度O(1)

注意事项

注意题目中说的是:满足 xstart ≤ x ≤ xend则该气球会被引爆。那么说明两个气球挨在一起不重叠也可以一起射爆

所以代码中 if (points[i][0] > points[i - 1][1]) 不能是>=

我是程序员Carl,可以找我组队刷题,也可以在B站上找到我,本文leetcode刷题攻略已收录,更多精彩算法文章尽在公众号:代码随想录,关注后就会发现和「代码随想录」相见恨晚!

如果感觉题解对你有帮助,不要吝啬给一个👍吧!