发糖果

力扣题目链接(opens new window)

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

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

  • 每个孩子至少分配到 1 个糖果。
  • 相邻的孩子中,评分高的孩子必须获得更多的糖果。

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

示例 1:

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

示例 2:

  • 输入: [1,2,2]
  • 输出: 4
  • 解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这已满足上述两个条件。

思路

根据示例1、2来看,我们只需要对满足规则的两种情况发放糖果即可,目标是在满足规则的前提下消耗最少的糖果(因此发的糖果数量有可能是不公平的)

怎么做呢?其实也简单,就是遍历数组,比较前后元素的大小关系,由此分配糖果即可

但是细想一下,遍历过程也是有坑的

举个例子:

从左往右遍历ratings数组,得到每个小孩应该分配的糖果数【左边孩子与右边孩子相比得出的结果】

此时的贪心:

局部最优:只要右边评分比左边大(ratings[i] > ratings[i - 1]),右边的孩子就多一个糖果

全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

//从左往右遍历ratings数组,左边孩子与右边孩子相比
for(int i = 1; i < ratings.size(); ++i){//从下标1开始
if((ratings[i] > ratings[i - 1]) candyCount[i] = candyCount[i - 1] + 1;
}

但是,下标4和5位置,下标5的评分比4低,但是获得的糖果数一样,这不满足规则

所以还要从右往左遍历一遍【右边孩子与左边孩子相比得出的结果】,综合之后取最大值得出要分配的糖果数

此时的贪心:

局部最优:只要左边评分比右边大(ratings[i] > ratings[i + 1]),左边的孩子就多一个糖果

全局最优:相邻的孩子中,评分高的左孩子获得比右边孩子更多的糖果

//从右往左遍历ratings数组,右边孩子与左边孩子相比
for(int i = ratings.size() - 2; i >= 0; --i){//从倒数第二个下标开始
if(ratings[i] > ratings[i + 1]){
candyCount[i] = max(candyCount[i + 1] + 1, candyCount[i]);//取当前糖果数与之前的最大值
}
}

在第二个循环中,当当前孩子的评分高于右边孩子时,当前孩子需要得到的糖果数应该是右边孩子已经获得的糖果数加上一颗糖果。但是由于在从左到右第一次遍历中已经分配了一部分糖果,所以当前孩子最少也会拿到和左边孩子一样多的糖果数,因此需要取 candyCount[i + 1] + 1 和 candyCount[i] 中的较大值作为当前孩子最终得到的糖果数。其中 candyCount[i + 1] + 1 表示右边孩子已经获得的糖果数加上一颗糖果, candyCount[i] 表示当前孩子之前分配的糖果数,也就是至少能够得到的糖果数。这样可以保证分配的糖果数满足题目要求,并且不浪费糖果数量。

注意:将右边孩子和左边孩子相比时,必须从右往左遍历,不能从左往右然后通过改下标的方式来比较

代码

本题仍然采用了两次贪心策略

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

两次贪心最终可以得到满足规则的糖果分配数

步骤如下:

1、创建糖果数统计数组

2、从左往右遍历ratings数组,左边孩子与右边孩子相比

3、从右往左遍历ratings数组,右边孩子与左边孩子相比

4、统计糖果数

class Solution {
public:
int candy(vector<int>& ratings) {
//定义糖果统计数组
vector<int> candyCount(ratings.size(), 1);//默认给一个糖
//从左往右遍历ratings数组,左边孩子与右边孩子相比
for(int i = 1; i < ratings.size(); ++i){//从下标1开始
if(ratings[i] > ratings[i - 1]) candyCount[i] = candyCount[i - 1] + 1;
} //从右往左遍历ratings数组,右边孩子与左边孩子相比
for(int i = ratings.size() - 2; i >= 0; --i){//从倒数第二个下标开始
if(ratings[i] > ratings[i + 1]){
candyCount[i] = max(candyCount[i + 1] + 1, candyCount[i]);
}
}
//统计糖果数
int res = 0;
for(int c : candyCount) res += c;
return res;
}
};

在第二个for循环中,遍历的是从右到左的顺序,所以需要从数组的最后一个元素的前一个元素开始,即从 ratings.size() - 2 的位置开始遍历。如果从最后一个元素开始遍历,那么就只能判断这个元素和它左边的元素之间的大小关系,而无法判断它和右边元素之间的大小关系,因为右边已经没有元素了。

【LeetCode贪心#07】分糖果(两个维度)的更多相关文章

  1. [LeetCode] Distribute Candies 分糖果

    Given an integer array with even length, where different numbers in this array represent different k ...

  2. LeetCode之小孩分糖果

    给定一群站好队的小孩而且按某项分值排名(姑且如果为年龄吧),年龄大的要比他身边年龄小的拿的糖要多.求怎么分配糖果使得分配的糖果数最少. 用一个数组从左到右再从右到左的遍历,向前遍历时若右边的比左边的大 ...

  3. [LeetCode] Candy (分糖果),时间复杂度O(n),空间复杂度为O(1),且只需遍历一次的实现

    [LeetCode] Candy (分糖果),时间复杂度O(n),空间复杂度为O(1),且只需遍历一次的实现 原题: There are N children standing in a line. ...

  4. LeetCode 1103. Distribute Candies to People (分糖果 II)

    题目标签:Math 题目让我们分发糖果,分的糖果从1 开始依次增加,直到分完. for loop可以计数糖果的数量,直到糖果发完.但是还是要遍历array 给people 发糖,这里要用到 index ...

  5. Java实现 LeetCode 575 分糖果(看看是你的长度小还是我的种类少)

    575. 分糖果 给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果.你需要把这些糖果平均分给一个弟弟和一个妹妹.返回妹妹可以获得的最大糖果的种类数. 示例 1: 输入 ...

  6. CSDN 分糖果算法的思路和求助

    昨天晚上 在csdn上做了一道分糖果的题目,我自个测的是没有问题,但是提交答案后,老失败,提示 你的程序正常运行并输出了结果,但是答案错误你的程序输出结果与测试数据中的输出结果不符 我先把自个思路说一 ...

  7. hunnu11543:小明的烦恼——分糖果

    Problem description   小明在班里一直是个非常公正的孩子.这点同学和老师都非常清楚,这不,老师每周都会从家里带来一些糖果.然后叫小明把糖果分给其它小朋友,但这个班里的同学都有一个非 ...

  8. 牛客 2018NOIP 模你赛2 T2 分糖果 解题报告

    分糖果 链接:https://www.nowcoder.com/acm/contest/173/B 来源:牛客网 题目描述 \(N\) 个小朋友围成一圈,你有无穷个糖果,想把其中一些分给他们. 从某个 ...

  9. 51nod——1402最大值、2479小b分糖果 (套路)

    1402最大值:正向从1到n,如果没有限制,就依次递增1,如果有限制,就取那个限制和递增到这的最小值.这样保证1和每个限制点后面都是符合题意的递增,但是限制点前面这个位置可能会有落差(之前递增多了). ...

  10. Leetcode(4)寻找两个有序数组的中位数

    Leetcode(4)寻找两个有序数组的中位数 [题目表述]: 给定两个大小为 m 和 n 的有序数组 nums1 和* nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O( ...

随机推荐

  1. 【转帖】如何使用route管理路由表

    这里是引用 route快捷使用方法 我们一般管理路由有使用route命令 本身route使用大致有两种方法:但其实 在实际操作中,我们熟练掌握一种方法就可以了. route 有以下6种操作方法: 1) ...

  2. ipset的学习与使用

    ipset的学习与使用 场景说明 虽然可以通过: firewall-cmd --zone=trusted --add-source=$1 --permanent && firewall ...

  3. redis 6源码解析之 object

    redis对象作为redis存储的基本单元,对应redisDb->dict 中的dictEntry->key和dictEntry->val. 更全面的图谱 源码解析参见:object ...

  4. alertmanager远程配置

    用于远程配置alertmanager的rules. 主要步骤为: 通过proxy更新mount的告警规则文件 重启容器 # ./client -h Note: Only for update exis ...

  5. Seata配置参考

    注意:mysql.redis等连接密码需修改为相应值 Seata-Server 环境 版本:1.4.2 OS: CentOS Linux release 7.5.1804 (Core) ip:192. ...

  6. .NET Core(C#) PadLeft和PadRight特定格式字符串长度补齐的方法和js中如何填充字符串

    .NET Core(C#) 1、PadLeft和PadRight使用说明 两个方法都是对字符串格式化进行补齐填充,PadLeft是左边,而PadRight是右边 '1010'.PadLeft(10,' ...

  7. springboot集成swagger之knife4j实战(升级版)

    官方文档链接:https://doc.xiaominfo.com/ 一.Knifej和swagger-bootstrap-ui对比 Knife4j在更名之前,原来的名称是叫swagger-bootst ...

  8. go中string是如何实现的呢

    go中string是如何实现的呢 前言 实现 go语言中的string是不可变的 []byte转string string转[]byte 字符串的拼接 +方式进行拼接 fmt 拼接 Join 拼接 b ...

  9. python中--try except 异常捕获以及正则化、替换异常值

    1.异常处理过程 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exceptio ...

  10. PaddleHub--{超参优化AutoDL Finetuner}【二】

     相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨: ...