LeetCode 面试经典 150_区间_用最少数量的箭引爆气球(51_452_C++_中等)(求交集)(sort() 以第二个进行排序)
LeetCode 面试经典 150_区间_用最少数量的箭引爆气球(51_452_C++_中等)
- 题目描述:
- 输入输出样例:
- 题解:
- 解题思路:
- 思路一(求交集):
- 代码实现(思路一(求交集)):
- 以思路一为例进行调试
- 部分代码解读
题目描述:
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
输入输出样例:
示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。
示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。
示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2]和[2,3]。
- 在x = 4处射出箭,击破气球[3,4]和[4,5]。
提示:
1 <= points.length <= 105
points[i].length == 2
-231 <= xstart < xend <= 231 - 1
题解:
解题思路:
思路一(求交集):
1、该题就是从左往右求区间的交集,若左右两区间无交集,则左区间需射一箭。
- 首先区间按照区间的开始进行排序
- 从前往后求每一个最大公共交集。求出一个公共交集弓箭数 +1
- end来代表最大公共交集的末尾
例:points = [[10,16],[2,8],[1,6],[7,12]]
- sort(points)= [[1,6],[2,8],[7,12],[10,16]]
- 此时需要一只箭,当前最大公共交集 [1,6],end=6
- 2 < end(6) 当前最大公共交集 [2,6],end=6
- 7 > end(6) 此时需要一只新的箭,当前新的最大公共交集 [7,12],end=12
- 10 < end(12) 当前最大公共交集 [10,12],end=12
2、复杂度分析:
① 时间复杂度:O(nlogn),排序操作的时间复杂度是O(nlogn),遍历操作的时间复杂度是 O(n)。
② 空间复杂度: O(logn),排序过程中递归栈的空间复杂度。
代码实现(思路一(求交集)):
class Solution {
public:// 函数用于计算最少的箭矢数,能够射穿所有气球int findMinArrowShots(vector<vector<int>>& points) {// 如果 points 为空,说明没有气球,返回0箭矢if (points.empty()){return 0;}// 对气球的区间进行排序,按照区间的起始位置升序排列sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {return u[0] < v[0]; // 比较两个区间的起始位置});// 初始化箭矢数为1,第一支箭射中第一个气球int ans = 1;// 设置当前箭矢能射中的气球区间的结束位置为第一个气球的结束位置int end = points[0][1];// 从第二个气球开始遍历for (int i = 1; i < points.size(); i++) {// 如果当前气球的起始位置大于之前气球的结束位置,说明需要再射一箭if (points[i][0] > end) {end = points[i][1]; // 更新箭矢射中的区间的结束位置ans++; // 增加箭矢数} else {// 否则,更新当前箭矢能射中的区间的结束位置// 取当前气球结束位置和之前气球的结束位置的最小值,更新射中的区间end = min(end, points[i][1]);}}// 返回最小的箭矢数return ans;}
};
以思路一为例进行调试
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;class Solution {
public:// 函数用于计算最少的箭矢数,能够射穿所有气球int findMinArrowShots(vector<vector<int>>& points) {// 如果 points 为空,说明没有气球,返回0箭矢if (points.empty()){return 0;}// 对气球的区间进行排序,按照区间的起始位置升序排列sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {return u[0] < v[0]; // 比较两个区间的起始位置});// 初始化箭矢数为1,第一支箭射中第一个气球int ans = 1;// 设置当前箭矢能射中的气球区间的结束位置为第一个气球的结束位置int end = points[0][1];// 从第二个气球开始遍历for (int i = 1; i < points.size(); i++) {// 如果当前气球的起始位置大于之前气球的结束位置,说明需要再射一箭if (points[i][0] > end) {end = points[i][1]; // 更新箭矢射中的区间的结束位置ans++; // 增加箭矢数} else {// 否则,更新当前箭矢能射中的区间的结束位置// 取当前气球结束位置和之前气球的结束位置的最小值,更新射中的区间end = min(end, points[i][1]);}}// 返回最小的箭矢数return ans;}
};int main(int argc, char const *argv[])
{// 测试数据:气球的起始和结束位置vector<vector<int>> points = {{10, 16}, {2, 8}, {1, 6}, {7, 12}};// 创建 Solution 类的实例,调用 findMinArrowShots 函数Solution s;cout << s.findMinArrowShots(points) << endl; // 输出最少的箭矢数return 0;
}
部分代码解读
sort() 以第二个进行排序
sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>& v) {return u[1] < v[1]; // 比较两个区间的结束位置
});
LeetCode 面试经典 150_区间_用最少数量的箭引爆气球(51_452)原题链接
欢迎大家和我沟通交流(✿◠‿◠)