• 贪心算法例子


    一、含义

    贪心算法是指在对问题求解时,总是作出在当前看来是最好的选择。也就是不从整体最优解上加以考虑,只考虑局部最优解。

    二、算法思路

    • 建立数学模型描述问题
    • 把求解的问题分成若干个子问题
    • 对每个子问题求解,得到子问题的局部最优解
    • 把子问题的解局部最优解合成原来解问题的一个解

    贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做依次贪心选择,就将所求问题简化为一个规模更小的子问题。通过每一步贪心选择,可得到问题的一个最优解。虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不用回溯。

    三、算法特性

    1. 有一个以最优方式来解决的问题。为了构造问题的解决方法,有一个候选对象集合:比如不同面值的硬币。
    2. 随着算法的进行,将积累起其他两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。
    3. 有一个函数来检查一个候选对象的集合是否提供了问题的解答。该函数不考虑此时的解决方法是否最优。
    4. 还有一个函数检查是否一个候选对象的集合是否是可行的,即是否可能往该集合上添加更多的候选对象以获得一个解。和上一个函数一样,此时不考虑解决方法的最优性。
    5. 选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。
    6. 最后,目标函数给出解的值。

    四、使用条件

    1、贪心选择性质:一个问题的最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。

    2、最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。

    五、例题

    分发糖果:n个孩子站成一排。给你一个整数数组ratings表示每个孩子的评分。需要按照以下要求,给这些孩子分发糖果:

    • 每个孩子至少分配到1个糖果。
    • 相邻两个孩子评分更高的孩子会获得更多的糖果。

    请你给每个孩子分发糖果,计算并返回需要准备的最少糖果数量。

    方法一:两次遍历

    相邻两个孩子评分更高的孩子会获得更多的糖果 这句话可以拆分为两个规则分别处理:

    (1)左规则:当ratings[i-1]

    (2)右规则:当ratings[i]>ratings[i+1]时,i号学生的糖果数量将比i+1号孩子的糖果数量多。

    遍历该数组两次,处理出每一个孩子分别满足左右规则时,最少需要被分得的糖果数量。最终每个人分的的糖果数量即为这两个数量的最大值。

    1. /**
    2. * @param {number[]} ratings
    3. * @return {number}
    4. */
    5. var candy = function(ratings) {
    6. let res=0,arr=[]
    7. for(let i=0;ilength;i++){
    8. if(ratings[i]>ratings[i-1]){
    9. arr[i]=arr[i-1]+1
    10. }else{
    11. arr[i]=1
    12. }
    13. }
    14. let right=0
    15. for(let i=ratings.length-1;i>-1;i--){
    16. if(ratings[i]>ratings[i+1]){
    17. right++
    18. }else{
    19. right=1
    20. }
    21. res+=Math.max(arr[i],right)
    22. }
    23. return res
    24. };

    方法二:常数空间遍历

    糖果要尽量少给,从1开始累计,每次要么仍然是1,要么比相邻的同学多给1个。从左到右枚举每一个同学,记前一个同学分得的糖果数量为pre:

    • 如果当前同学比上一个同学评分高,说明我们就在最近的递增序列中,直接分配给该同学pre+1;否则就在递减序列中,直接分配给当前同学一个糖果,并把该同学所在的递减序列中所有的同学都再多分配一个糖果,以保证糖果数量还是满足条件。
    • 无需显式地额外分配糖果,只需记录当前的递减序列长度,即可知道需要额外分配的糖果数量。
    • 同时注意当当前的递减序列长度和上一个递增序列等长时,需要把最近的递增序列的最后一个同学也并进递减序列中。

    这样,只要记录当前递减序列的长度dec,最近的递增序列长度inc和前一个同学分得的糖果数量pre即可。

    1. var candy = function(ratings) {
    2. const n = ratings.length;
    3. let ret = 1;
    4. let inc = 1, dec = 0, pre = 1;
    5. for (let i = 1; i < n; i++) {
    6. if (ratings[i] >= ratings[i - 1]) {
    7. dec = 0;
    8. if (ratings[i] === ratings[i - 1]) pre = 1;
    9. else pre++;
    10. ret += pre;
    11. inc = pre;
    12. } else {
    13. dec++;
    14. if (dec === inc) {
    15. dec++;
    16. }
    17. ret += dec;
    18. pre = 1;
    19. }
    20. }
    21. return ret;
    22. }

  • 相关阅读:
    【深圳1024开发者城市聚会定向征文】
    【HarmonyOS】应用通知广播的使用
    【BurpSuite】插件开发学习之J2EEScan - 汇总篇(主动+被动1-76)
    点集合的三角剖分
    【Unity】万人同屏高级篇, BRG & Jobs实战应用, 海量物体同屏
    【SVN】SVN服务端地址变动,idea切换SVN地址
    【Kafka】微服务学习笔记九:什么是消息中间件&Kafka的介绍及使用
    理解npm run dev 和 npm run serve的区别
    @RequiredArgsConstructor实现构造器注入
    AUTOSAR汽车电子嵌入式编程精讲300篇-基于 CAN 总线的车辆数据采集与远程监控系统研发(下)
  • 原文地址:https://blog.csdn.net/smell201611010513/article/details/126330192