欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【LeetCode刷题笔记-15 452:用最少数量的箭引爆气球】

程序员文章站 2022-04-04 09:44:49
...

题目:
【LeetCode刷题笔记-15 452:用最少数量的箭引爆气球】
今天我作弊了!因为上来思考了一会真的没有什么好的办法,但是看了题解以后又懂了。(这样学习到底有没有效率啊。。)

题解是这样考虑这个问题的:

1.首先,对于每一支箭,都要尽可能的引爆多的气球。那么我们假设所有的气球都是从>0的坐标点开始,如何确保我们能引爆更多的气球呢。只要保证每一支箭都是右边界最靠左的那个位置就行。

我和题解的思路不太相同,我是这么考虑这个问题的。随便画一张气球有重叠部分的图,假如我们的箭从0开始移动,那么为了引爆更多的气球,必然是在最靠左的右边界射出这支箭才行。因为如果超出了这个边界值,那么就需要多的一支箭回来单独引爆这个气球。

贪心的思想我认为就体现在这里:

既然每个气球都需要被引爆,那么在满足引爆 对箭限制最大的那个气球(因为它一定要被引爆,而箭和其它同时被引爆的气球 都可以迁就它,所以满足它是必须的) 的同时,引爆尽可能多其他的气球。

在付出不变的的前提下,获得尽可能多。—引用自评论区用户hlx

于是,我们可以对点进行右边界升序排列,然后就可以每一次都比对找出第一个起点大于射箭位置的气球,并将它的位置放置到右断点即可保证是右边界最靠左的那个位置(因为已经按照右边界升序排列过了)

最后再提一句,如果是贪心思想的话,**同样的道理,也可以找到所有左边界最靠右的那个点做发射点。**因为要在限制最大的条件下找出引爆最大值的话,这样做感觉也是可以的。但我并没有去验证为什么可以,因为实在想不到怎么去证明这两种做法得到的点的个数是一样的。如果有大佬能证明,请在评论区指个路,谢谢!

最后就是算法(C++)附带测试;

#include<iostream>
#include<algorithm>
using namespace std;

class Solution {
public:
    int findMinArrowShots(vector<vector<int > >& points) {
		if (points.empty()) {//如果为空则直接返回 
            return 0;
        }
        sort(points.begin(),points.end(),[](const vector<int>& u,const vector<int>& v){
        	return u[1]<v[1];//按照右边界升序排列 
		});
		
		int ans = 1;//从第一支箭开始计数
		int pos = points[0][1];//第一支发射的箭在第一个气球的右边界(因为是升序排列,所以可以保证是最左边的右边界)
		for(const vector<int>& ballon:points){//使用迭代器访问气球元素 
			if(ballon[0]>pos){//找到第一个左边界超出当前箭射出位置的气球 
				ans++;
				pos = ballon[1]; 
			} 
		}
		return ans;
    }
};

int main()
{
	vector<vector<int > > points = {{10,16},{2,8},{1,6},{7,12}};
	Solution s;
	int ans = s.findMinArrowShots(points);
	cout<<ans;
}
相关标签: 算法 c++