2.算法-贪心算法,分配问题(leetcode455发饼干,135发糖果),区间问题(435无重叠区间),练习(605种花,452射气球,122 买卖股票)

本文探讨了如何运用贪心算法解决一系列分配问题,如分发饼干、分发糖果、无重叠区间等。通过排序和比较策略,确保每次操作都是局部最优,从而达到全局最优解。此外,还分析了买卖股票问题,展示了如何预知利润最大化。总结了各个问题的优化点和关键代码实现,强调了在解决此类问题时,排序和局部最优的重要性。
摘要由CSDN通过智能技术生成

一 算法解释

保证每次操作都是局部最优,局部结果互不相干,全局结果是局部结果的简单求和,从而使最后得到的结果是全局最优的。

二 分配问题

例1:leetcode题455,分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
在这里插入图片描述

1.题目分析:
从胃口小(数组g中最小的)的开始分配,在饼干里找能满足其胃口的且最小的(即数组中大于g【i】且最小的)分给他,然后再考虑剩下的。
贪心策略:每次给剩余孩子里胃口最小的分配能满足胃口的最小饼干

2.优化:
由于两个数组都需找出最小的,且需获得大小关系,如果直接循环遍历两次,容易一开始取到胃口最大的小孩,所以应在开始判定之前,将两个数组都由小到大排序。这样 就可以从头开始分别遍历。
然后这里如果用双层for 的话,情况会很复杂,首先两个数组谁长谁短,每个循环何时结束?都不好判断,而且可能会重复遍历。
所以这个题目用while(numchild<g.size() && numcookie<s.size() ),一旦有一个遍历结束就结束,即要么孩子先没了,要么第一个孩子胃口大于最大的饼干,后面的孩子就都吃不了。
然后符合情况的numchild++,否则就一直numcookie++

3.sort()排序函数

sort(first_pointer,first_pointer+n,cmp)

3.2 功能:该函数可以给数组,或者链表list、向量排序。

3.3 实现原理:sort并不是简单的快速排序,它对普通的快速排序进行了优化,此外,它还结合了插入排序和推排序。系统会根据你的数据形式和数据量自动选择合适的排序方法,这并不是说它每次排序只选择一种方法,它是在一次完整排序中不同的情况选用不同方法,比如给一个数据量较大的数组排序,开始采用快速排序,分段递归,分段之后每一段的数据量达到一个较小值后它就不继续往下递归,而是选择插入排序,如果递归的太深,他会选择推排序。

3.4参数:
此函数有3个参数:
参数1:第一个参数是数组的首地址,一般写上数组名就可以,因为数组名是一个指针常量。

参数2:第二个参数相对较好理解,即首地址加上数组的长度n(代表尾地址的下一地址)。

参数3:默认可以不填,如果不填sort会默认按数组升序排序。也就是1,2,3,4排序。也可以自定义一个排序函数,改排序方式为降序什么的,也就是4,3,2,1这样。

3.5使用
使用此函数需先包含:

#include <algorithm>

并且导出命名空间:

using namespace std;

简单例子:对数组A的0~n-1元素进行升序排序,只要写sort(A,A+n)即可;对于向量V也一样,sort(v.begin(),v.end())即可。题目中给的是两个向量gs,所以我们使用向量排序。
在这里插入图片描述
4.代码

class Solution {
   
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
   
        sort(g.begin(),g.end());//排序
        sort(s.begin(),s.end());
       int numchild=0;
       int numcookie=0;
       while(numchild<g.size() && numcookie<s.size() )//一旦有一个结束就结束
       {
   
           if(g[numchild]<=s[numcookie]) numchild++;
           numcookie++;//不管孩子吃没吃,饼干始终只能用一次,因为吃的了的话饼干没了得到下一块饼干,吃不了的话上一个胃口小的孩子吃不了下一个胃口大的孩子更吃不了。
       }
       return numchild;
    }
};

5.总结:
1.在开始判定之前,先对数组和字符串进行排序是常见操作,方便之后大小比较。
2.若对连续空间变量进行操作,不区分数组和字符串,因为其本质上都是在连续空间上的有序变量集合。字符传“zfc”可以被看成数组【‘z’,‘f’,‘c’】

例2:135.分发糖果

老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。

你需要按照以下要求,帮助老师给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。

那么这样下来,老师至少需要准备多少颗糖果呢?

在这里插入图片描述
1.题目分析
1.1
每个孩子至少分配到1个糖果,所以n个孩子至少一开始数目就是n。
1.2
首先明确这个问题没有办法先排序,因为学生的站位会影响到糖果数目。接下来是两侧的问题,我们可以考虑把两侧分开来考虑:
第一次for,从头开始,如果右大于左,则右加一
第二次for,从尾开始,如果左大于右,则左加一
(那么这样说的话如果只有一个人,或者没有人,不需要遍历,直接返回.size()即可)

2.优化
一开始我的思路,在加一方面草率了,不能单独设置一个num一直加,应该给每个小孩

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值