一、题目简述
在二维平面有一些气球,输入数据是每个气球在水平方向上的起点和终点,假设竖直方向上的空间足够,起点总是小于终点,最多有
104
个球.
一支箭能够从X轴的不同位置垂直射出。若射出点为x,则满足
xstart≤x≤xend
的气球将会被被射穿。射箭的次数没有限制。一支箭每次能够射穿的气球数没有限制。问射穿所有气球所需要的最少的箭是几支?
例如:
输入:
[[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:实例中的一种射箭方式为,首先在x=6处射箭(将气球
[2,8][1,6]
射穿),其次在x=11处射箭(射穿另外两个气球)。
二、编程思路
2.1 贪心算法简介
- 贪心算法:每一步都选择当前状态下最好或最优的选择,从而导致结果是最好或最优的算法(贪心算法)。
- 贪心算法在有最优子结构的问题中尤为有效,最优子结构即局部最优解能够决定全局最优解。简单来说就是问题能够分解为子问题来解决,子问题的最优解能够递归到最终问题的最优解。
- 贪心算法与动态规划的不同之处在于他对每个子问题的解决方案都做出了选择,不能回退。动态规划则会保存以前的计算结果,并根据以前的结果对当前进行选择,具有回退功能。
2.2 贪心算法一般步骤
- 建立数学模型来描述问题
- 将求解的问题分解为若干个子问题
- 对每一个子问题求解,得到子问题的局部最优解
- 将子问题的局部最优解合成为原来问题的解
2.3本题设计思路
由于不考虑气球垂直方向上的高度,因此可以将其视为线段。给定每个气球的起点和终点的集合 points ,第一步要做的便是对其进行排序,排序的两个原则:
- 起点小的在前
- 起点相同,终点小的在前
其次寻求将原始问题分解为子问题的过程,开始时的思路是每次在气球重叠处最多的地方射箭,之后递归,但是此种方法实现起来相对复杂。网上题解实现的方法是从左到右,保证每次射箭能够击中最多数量的气球,此种方法只需遍历一次即可。
三、代码设计
typedef pair<int,int> p;
bool cmp(p p1,p p2){
if(p1.first!=p2.first){
return p1.first<p2.first;
}
else{
return p1.second<p2.second;
}
}
class Solution {
public:
int findMinArrowShots(vector<pair<int, int> >& points) {
if(points.size()==0) return 0;
sort(points.begin(),points.end(),cmp);
int minArrow=1;
int rightBound=points[0].second;
for(int i=1;i<points.size();i++){
// cout<<points[i].first<<" "<<points[i].second<<endl;
if(points[i].first<=rightBound){
rightBound=min(rightBound,points[i].second);
}
else{
minArrow++;
rightBound=points[i].second;
}
}
return minArrow;
}
};
四、实验心得
贪心算法中最重要是能够找到合适且正确的子问题,从而对原始问题进行分解。