每日一题:贪心算法解分发糖果问题

一,问题描述:

题目:Leetcode 第135题

难度:困难

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

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

每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目

示例1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
     第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

提示:

  • n == ratings.length
  • 1 <= n <= 2 * 104
  • 0 <= ratings[i] <= 2 * 104

二,解答:

这道题目有三个条件:

1,每个孩子至少一颗糖

2,相邻的孩子,评价高的得到的糖更多

3,求糖果数量最小值

为满足条件3,则相邻小孩评价高的多得一颗糖即可。

首先我们考虑从左到右一次遍历,那么会有三种情况:

1. 当前孩子的评分比左边的高,也就是递增的,那么当前孩子的糖果数量要比左边个多1。

2. 当前孩子的评分等于左边孩子的评分,我们让他降为1,也就是说当前孩子的糖果是1,最 终是不是1,后面还需要在判断。

3. 当前孩子的评分低于左边孩子的评分,也就是递减的,这个我们就没法确定当前孩子的糖 果了,但我们可以统计递减孩子的数量(我们可以反向思考,这个递减的序列中,最后一 个肯定是1,并且从后往前都逐渐增加的)

顺着这条思路是可以做出来的,但我们可以换一条思路:

先从左向右遍历,再从右向左遍历一遍。

1,如果只比左边的值大,那么当前孩子的糖果数量要比左边孩子的糖果多1。

2,如果只比右边的值大,那么当前孩子的糖果数量要比右边孩子的糖果多1。

3,如果比左右两边都大,那么当前孩子的糖果数量要比左右两边最多的糖果还要多1。

第一次从左往右,如果右边的孩子比左边得分 高,那么右边的孩子糖果数量就要比左边的多1。这样每个孩子都能满足右边的条件,第二次从右向左,原理一样,只不过需要多用一个max,来满足第三个情况。

代码:

class Solution {
public:
    int candy(vector<int>& ratings) 
    {
        int n=ratings.size();
        //tg 表示每个孩子手上的糖果数量,且初始量为一
        vector<int> tg(n,1);
        //先从左往右遍历
        for(int i=1;i<n;i++)
        {
            if(ratings[i]>ratings[i-1])
            {
                tg[i]=tg[i-1]+1;
            }
        }
        //count表示总的糖果数
        //因为下一个循环没有遍历最后一个值,所以count初始为tg[n-1]
        int count=tg[n-1];
        //从右往左遍历,然后顺便累加total的值
        for(int j=n-2;j>=0;j--)
        {
            if(ratings[j]>ratings[j+1])
            {
                tg[j]=max(tg[j],tg[j+1]+1);
            }
            count+=tg[j];
        }
        return count;
    }
};

三,总结:

贪心算法只需要每一步做出局部最优解即可,如这道题中,如果孩子评价被左边的孩子高,就多个一颗糖果,否则就只给一颗糖果。当然与左边的比较完了之后,还要与右边的比较。唯一不同的是后一次比较,需要保证孩子的糖果数量要比左右两边其中有最多糖果的孩子还要多1。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别抢我的辣条~

老板大气!祝老板身体健康!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值