《代码随想录》Ⅷ 贪心算法 452. 用最少数量的箭引爆气球
革命尚未成功,同志仍需努力!
题目:力扣链接
-
我们有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组
points 中,其中points[i] = [xstart, xend] 表示第 i 个气球的水平直径在xstart 和xend 之间。我们不知道气球的确切 y 坐标。一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,如果一个气球的直径的开始和结束坐标为
xstart 和xend,且满足xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。弓箭一旦被射出之后,可以无限地前进。给定一个数组
points,返回引爆所有气球所必须射出的最小弓箭数。
一、思想
这道题的核心思想是使用贪心算法。具体来说:
-
区间重叠问题:将每个气球看作一个区间,问题转化为找到最少的点,使得每个区间至少包含一个点
-
排序策略:首先将所有区间按照起始点进行排序
-
合并重叠区间:遍历排序后的区间,维护当前箭能覆盖的最大范围:
- 如果新区间与当前范围有重叠,则更新范围右边界为两者较小值
- 如果没有重叠,则需要新增一支箭,并更新范围右边界
这种方法的正确性在于:
- 排序后可以保证每次处理都是最左的未覆盖区间
- 取最小右边界可以最大化后续区间的覆盖可能性
二、代码
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)的递归栈空间(取决于具体实现)
白展堂:人生就是这样,苦和累你总得选一样吧?哪有什么好事都让你一个人占了呢。 ——《武林外传》
1096

被折叠的 条评论
为什么被折叠?



