
初篇我们介绍了贪心算法的相关背景知识,本篇我们将结合具体题目,进一步深化大家对于贪心算法的理解和运用。
双倍(Double):将显示屏上的数字乘 2; 递减(Decrement):将显示屏上的数字减 1 。
将startValue 理解为begin,target理解为end
贪⼼策略:
正难则反:
当「反着」来思考的时候,我们发现:
i. 当 end <= begin 的时候,只能执⾏「加法」操作;
ii. 当 end > begin 的时候,对于「奇数」来说,只能执⾏「加法」操作;对于「偶数」来说,最好的⽅式就是执⾏「除法」操作这样的话,每次的操作都是固定唯一的
class Solution {
public:
int brokenCalc(int startValue, int target) {
int ret=0;//操作次数
while(target>startValue)
{
if(target%2==0) target/=2;//如果为偶数,直接除以二
else target++;//修正为偶数
ret++;
}
return ret+startValue-target;//注意次数并非直接返回ret
}
};解释:
观察测试样例可知,在合并为一个区间时,应该选取左区间尽可能小的,右区间尽可能大的进行合并,这样子可以保证最大化覆盖区间。
具体步骤如下:
左区间排序的方式先对整个数组intervals进行预处理,然后会发现,能够合并的区间,都是连续的并集的方式合并区间贪心策略:
由于区间已经按照「左端点」排过序了,因此当两个区间「合并」的时候,合并后的区间:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
//按照左端点进行排序
sort(intervals.begin(),intervals.end(),[&](vector<int> a,vector<int> b)
{
return a[0]<b[0];
});
int left=intervals[0][0],right=intervals[0][1];
int n=intervals.size();
vector<vector<int>> ret;//返回数组
for(int i=1;i<n;i++)
{
int a=intervals[i][0],b=intervals[i][1];
//判断是否存在重叠区间
if(right>=a)
{
right=max(right,b);//更新右端点
}
else//不存在重叠区间,直接添加
{
ret.push_back({left,right});
left=a,right=b;//更新左右端点
}
}
ret.push_back({left,right});//别忘了最后一个区间
return ret;
}
};本题与上题类型,但是本题要求是移除区间,同理,移除区间时应该选取左区间尽可能小的,右区间尽可能大的进行合并,这样子可以保证最大化覆盖区间
具体步骤如下:
贪⼼策略:
如何移除区间范围较⼤的区间:
由于已经按照「左端点」排序了,因此两个区间重叠的时候,我们应该移除「右端点较⼤」的区间.
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
int ret=0;
//按左端点进行排序
sort(intervals.begin(),intervals.end());
int left=intervals[0][0],right=intervals[0][1];
int n=intervals.size();
for(int i=1;i<n;i++)
{
int a=intervals[i][0],b=intervals[i][1];
//有重叠部分
if(a<right)
{
ret++;//删除一个区间
right=min(right,b);//更新右端点,注意删除较大的区间
}
else
//无重叠部分
{
left=a;
right=b;//更新端点,无需删除
}
}
return ret;
}
}; xstart ≤ x ≤ xend,则该气球会被 引爆 。最小 弓箭数 。翻译过后的题目分析如上,与合并区间类似,最终所需要的弓箭数量即为合并后的区间数量。
但是本题需要注意,相邻区间无法合并

并且,本题要求合并区间求的是交集,是气球都必须含有的公共部分。
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
int n=points.size();
if(n==1) return 1;//处理特殊情况
int ret=1;
sort(points.begin(),points.end());//按照左端点进行排序
int left=points[0][0],right=points[0][1];
for(int i=1;i<n;i++)
{
int a=points[i][0],b=points[i][1];
//有重叠部分
if(a<=right)
{
right=min(right,b);//求并集
}
else
//无重叠部分
{
ret++;
right=b;
}
}
return ret;
}
};本篇关于贪心算法的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!