求最值、求最优解的题目,一般可以用动态规划、贪心、二分来解决。贪心中常常先进行排序。
贪心的一大特点就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。
例题1
452用最少数量的箭引爆气球
考虑到每个气球都要被射中,所以射每个气球的时候,我们希望有尽量多的别的气球也被射到。迭代时,已经被射中的气球就跳过。
本题以左边界为标准进行排序,会导致如下的情况,射当前气球无法保证射爆所有与其有重叠的气球:
但是以右边界为标准进行排序,只要我在当前气球的右边界射一箭,那么就能射爆所有和其有重叠的:
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if(points.size()==0)
return 0;
sort(points.begin(),points.end(),[](vector<int>&A,vector<int>&B){return A[1]<B[1];});
int count=0;
int i=0;
while(i<points.size()){
//看后边有多少个和自己有重叠
int j=i+1;
int t=0;
while(j<points.size() && points[j][0]<=points[i][1]){
t++;
j++;
}
count++;
i+=1+t;
}
return count;
}
};
例题2
435无重叠区间
先以右边界进行排序(给剩下的区间留下最大的空间,以使得要删除的区间最少),删除所有与当前区间重叠的区间,留下当前区间(理由:因为当前区间的右边界最靠左,最能够给剩下区间留下最大空间)
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
int len=intervals.size();
if(len<=1)
return 0;
//对区间们进行从小到大排序,使用lambda表达式
sort(intervals.begin(),intervals.end(),[](vector<int>a,vector<int>b){
return a[1]<b[1];
});
int prev=intervals[0][1];
int chosen=1;
for(int i=1;i<len;i++){
//说明重叠了,抛弃
if(intervals[i][0]<prev){
continue;
}else{
chosen++;
prev=intervals[i][1];
}
}
return len-chosen;
}
};
例题3
1024视频拼接
这一题的贪心策略应该是:
先将所有区间按照左侧从小到大排序,左侧相同的,从大到小排序。初始覆盖范围是[0,r],从左到右遍历区间,每次用所有left<=r
中right最大的区间来更新r(保证了每次挑出最有用的区间来更新r)。
注意:这一题中有很多细节(坑),比如新的一轮开始时,如果left>r,则直接返回-1。此外,类似这种中间含有多个小周期的,用while更合适一些。
class Solution {
public:
int videoStitching(vector<vector<int>>& clips, int time) {
int len=clips.size();
if(len==0)
return 0;
sort(clips.begin(),clips.end(),[](vector<int>&A,vector<int>&B){
return A[0]<B[0] || A[0]==B[0] && A[1]>B[1]; //只写小于的条件,等于和大于都是false
});
int r=0;
int ans=0;
int i=0;
while(i<len){
if(r>=time)
return ans;
if(clips[i][0]>r)
return -1;
int t=clips[i][1];
int j=i;
for(;j<len && clips[j][0]<=r;j++){
t=max(t,clips[j][1]);
}
//能够更新r范围的情况下,加入结果集
if(t>r){
ans++;
r=t;
}
i=j;
}
return r>=time?ans:-1;
}
};
例题4
55跳跃游戏
贪心在这一题的体现:每一步都拓展当前能够到达的最远距离。
class Solution {
public:
bool canJump(vector<int>& nums) {
//不断计算能到达的最远距离
int farthest=0;
for(int i=0;i<nums.size()-1;i++){
farthest=max(farthest,i+nums[i]);
if(farthest<=i)
return false;
}
return true;
}
};