LeetCode452. Minimum Number of Arrows to Burst Balloons题解

1. 题目描述

LeetCode452. Minimum Number of Arrows to Burst Balloons题解_第1张图片
【翻译过来】:
有若干个气球,给出了它们的直径两个端点的坐标(X轴),我们的工作是需要用一支箭来戳破气球。例如两个气球的直径分别是(1,6)和(2,8),那么我们就可以在x=6的坐标处发射一支箭从而将它们一起戳破。求解的问题是:给出一系列气球直径的坐标之后,最少能用多少支箭就可以戳破它们。
LeetCode452. Minimum Number of Arrows to Burst Balloons题解_第2张图片

2. 样例

Input:
[[10,16], [2,8], [1,6], [7,12]]

Output:
2

Explanation:
One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).

3. 分析

题目的意思很明确,就是利用最少的箭来戳破气球。分析一下,我们不难得到这样的结论:我们对所有的气球所在的位置进行整理,如果发现两个气球有重叠的部分,就说明它们有可能被同一支箭戳破。
有了这样的一个概念,接下来就是具体做法:我们将所有的气球按照它们的直径左端点进行升序排列,这样我们得到的序列就有了很好的性质:后一个气球很有可能与前一个气球重合。
接下来,我们可以用这样的方法:我们维护一个reference参考区间,这个区间代表的是目前为止最小的气球重合部分,即如果发射箭的话,射箭的坐标就应该在这个reference区间里面,如果接下来的气球左端点都不在这个区间里面,那么它就不会和之前的若干个气球一起被射中了,就要用新的箭。
即:这个贪心算法的思想就是:目前reference参考区间维护的是到目前为止能够被一起射中的气球的重叠部分。
进行遍历的时候:判断当前气球的左右坐标与reference区间关系:

  • 如果该气球在区间内部,说明该气球可以和之前的气球一起被射中,区间需要缩小至该气球的左右端点;
  • 如果左端点在区间内部,右端点不在,说明该气球有一部分和区间重合,所以区间需要缩小:右端点不变,左端点为该气球的左端点;
  • 如果左端点不在区间内部,说明该气球与之前的气球不能一起被射中,需要新增一支箭,之前的气球都被戳破,reference变为该气球区间重新探寻;
    LeetCode452. Minimum Number of Arrows to Burst Balloons题解_第3张图片

4. 源码

class Solution {
public:
    static bool Compare(pair<int, int>point1, pair<int, int>point2) {
        if (point1.first <= point2.first) {
            if (point1.first == point2.first) {
                return point1.second < point2.second;
            }
            return true;
        }
        return false;
    }

    int findMinArrowShots(vectorint, int>>& points) {
        int counter = 1;
        sort(points.begin(), points.end(), Compare);
        pair<int, int>reference;
        if (points.size() != 0) {
            reference = points[0];
        }
        for (int i = 0; i < (int)points.size(); i++) {
            if (points[i].first <= reference.second) {
                if (points[i].second <= reference.second) {
                    reference.first = points[i].first;
                    reference.second = points[i].second;
                }
                else {
                    reference.first = points[i].first;
                }
            }
            else {
                counter++;
                reference = points[i];
            }
        }
        if (points.size() == 0) {
            return 0;
        }
        return counter;
    }
};

5. 心得

这道题,我自己设计的解法居然能够打败98.95%的人,有点小开心。尽管刚开始走了一点弯路:认为只要每一个气球与前一个气球有重叠部分就可以一起射中,这个错误的思路导致了我提交了3次的Wrong Answer,因为只与前一个气球重叠,不代表和再之前的能够重叠。

你可能感兴趣的:(算法题解)