当前位置: 首页 > news >正文

LeetCode 面试经典 150_数组/字符串_分发糖果(15_135_C++_困难)(贪心算法)

LeetCode 面试经典 150_数组/字符串_分发糖果(15_135_C++_困难)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(贪心算法):
      • 代码实现
        • 代码实现(思路一(贪心算法)):
        • 代码实现(对思路一代码进行优化):
        • 以思路一为例进行调试

题目描述:

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 * 109
0 <= ratings[i] <= 2 * 109

题解:

解题思路:

思路一(贪心算法):

1、左右代表相邻的两个元素(只考虑两个相邻元素)
->->->->->->->
左 > 右 ;右=1
左 < 右 ;右=左+1
左 = 右 ;右=1
<-<-<-<-<-<-<-
左 > 右 ;左=右+1
左 < 右 ;左=1
左 = 右 ;左=1
① 从 左->右 扫描时,先将每个孩子的糖果置为 1,如果相邻元素中右侧的元素比左侧大,则右侧元素的糖果数等于左侧糖果数+1。
② 从 右->左 扫描时,先将每个孩子的糖果置为 1,如果相邻元素中左侧的元素比右侧大,则左侧元素的糖果数等于右侧糖果数+1。
③ 再挑选出 左->右 和 右->左中较大的元素。

:ratings = [1,0,2],left 代表从左到右,right 代表从右到左。
left = [1,1,2]
right= [2,1,1]
ans = 2+1+2=5

2、复杂度分析:
① 时间复杂度:O(n),n 代表数组的长度,遍历三遍数组。
② 空间复杂度:O(n),n 代表数组的长度,使用 left 存储从左向右的糖果,使用 right 存储从右向左的糖果。

代码实现

代码实现(思路一(贪心算法)):
class Solution1 {
public:// 主函数,返回给定评分数组所需的糖果总数int candy(vector<int>& ratings) {int count = ratings.size(); // 获取评分数组的长度vector<int> left(count, 1); // 初始化一个长度为count的数组left,表示每个孩子至少有1颗糖// 从左到右遍历评分数组,计算每个孩子的糖果数(如果比前一个孩子的评分高,糖果数加1)for (int i = 1; i < count; i++) {if (ratings[i] > ratings[i - 1]) { // 如果当前孩子的评分高于前一个孩子left[i] = left[i - 1] + 1; // 当前孩子的糖果数比前一个孩子多1}}vector<int> right(count, 1); // 初始化一个长度为count的数组right,表示每个孩子至少有1颗糖// 从右到左遍历评分数组,计算每个孩子的糖果数(如果比下一个孩子的评分高,糖果数加1)for (int i = count - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) { // 如果当前孩子的评分高于下一个孩子right[i] = right[i + 1] + 1; // 当前孩子的糖果数比下一个孩子多1}}int ans = 0; // 用于存储总糖果数// 遍历所有孩子,取每个孩子在left和right数组中的最大值(这保证了当前孩子能够得到最大可能的糖果数)for (int i = 0; i < count; i++) {ans += max(left[i], right[i]); // 取最大值,避免重复计算}return ans; // 返回总糖果数}
};
代码实现(对思路一代码进行优化):
/** 优化存储空间(只使用一个额外的数组)* 只使用一个额外的数组存储 左->右 扫描的结果* 从 右->左 扫描时,边计算 右->左 的糖果数量,边计算ans(总糖果数)* 时间复杂度:O(n),遍历了两遍数组。* 空间复杂度:O(n),使用了一个额外的数组空间。*/
class Solution2 {
public:// 主函数,返回给定评分数组所需的糖果总数int candy(vector<int>& ratings) {int count = ratings.size(); // 获取评分数组的长度vector<int> left(count, 1); // 初始化一个长度为count的数组left,表示每个孩子至少有1颗糖// 从左到右遍历评分数组,计算每个孩子的糖果数(如果比前一个孩子的评分高,糖果数加1)for (int i = 1; i < count; i++) {if (ratings[i] > ratings[i - 1]) { // 如果当前孩子的评分高于前一个孩子left[i] = left[i - 1] + 1; // 当前孩子的糖果数比前一个孩子多1}}// 初始化右边的糖果数,先假设最后一个孩子右边没有其他孩子int ans = left[count-1];  // 初始总糖果数为最后一个孩子的糖果数int right = 1;  // 右侧的临时糖果数,初始化为1,因为每个孩子至少有1颗糖// 从右到左遍历评分数组,计算每个孩子的糖果数(如果比下一个孩子的评分高,糖果数加1)for (int i = count - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) { // 如果当前孩子的评分高于下一个孩子right = right + 1; // 当前孩子的糖果数增加} else {right = 1; // 如果当前孩子的评分不高于下一个孩子,糖果数恢复为1}// 更新总糖果数:取左边和右边糖果数的最大值// left[i]是从左到右计算的糖果数,right是从右到左计算的糖果数ans += max(right, left[i]); // 累加当前孩子的最大糖果数}return ans; // 返回总糖果数}
};
以思路一为例进行调试
#include<iostream>
#include<vector>
using namespace std;class Solution1 {
public:// 主函数,返回给定评分数组所需的糖果总数int candy(vector<int>& ratings) {int count = ratings.size(); // 获取评分数组的长度vector<int> left(count, 1); // 初始化一个长度为count的数组left,表示每个孩子至少有1颗糖// 从左到右遍历评分数组,计算每个孩子的糖果数(如果比前一个孩子的评分高,糖果数加1)for (int i = 1; i < count; i++) {if (ratings[i] > ratings[i - 1]) { // 如果当前孩子的评分高于前一个孩子left[i] = left[i - 1] + 1; // 当前孩子的糖果数比前一个孩子多1}}// 初始化右边的糖果数,先假设最后一个孩子右边没有其他孩子int ans = left[count-1];  // 初始总糖果数为最后一个孩子的糖果数int right = 1;  // 右侧的临时糖果数,初始化为1,因为每个孩子至少有1颗糖// 从右到左遍历评分数组,计算每个孩子的糖果数(如果比下一个孩子的评分高,糖果数加1)for (int i = count - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) { // 如果当前孩子的评分高于下一个孩子right = right + 1; // 当前孩子的糖果数增加} else {right = 1; // 如果当前孩子的评分不高于下一个孩子,糖果数恢复为1}// 更新总糖果数:取左边和右边糖果数的最大值// left[i]是从左到右计算的糖果数,right是从右到左计算的糖果数ans += max(right, left[i]); // 累加当前孩子的最大糖果数}return ans; // 返回总糖果数}
};int main(int argc, char const *argv[])
{vector<int> ratings = {1,0,2};Solution1 s;cout<<s.candy(ratings);return 0;
}

LeetCode 面试经典 150_数组/字符串_分发糖果(15_135)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

http://www.xdnf.cn/news/1267759.html

相关文章:

  • 【Redis7.x】docker配置主从+sentinel监控遇到的问题与解决
  • GPT-5:数字大脑的进化史
  • 1393. 与7无关的数?
  • 【Linux】Tomcat
  • 八、Linux Shell 脚本:变量与字符串
  • jupyter服务器创建账户加映射对外账户地址
  • 2025-08-09 李沐深度学习12——卷积神经网络基础
  • Zabbix自动注册:轻松实现大规模监控
  • Vue3环境搭建+Mybatis-plus的使用
  • 【ref、toRef、toRefs、reactive】ai
  • 具体数学:和式(四)求和的一般方法
  • 【linux基础】Linux目录和Windows目录的区别
  • Openlayers基础教程|从前端框架到GIS开发系列课程(19)地图控件和矢量图形绘制
  • SimBA算法实现过程
  • GitHub第三方登录全解析:OAuth 2.0流程详解(适合初学者)
  • 华为实验: 单区域/多区域OSPF
  • 华为实验-VLAN基础
  • ComfyUI——舒服地让大模型为我所用
  • 微信原生小程序 Timeline 组件实现
  • AI大语言模型在生活场景中的应用日益广泛,主要包括四大类需求:文本处理、信息获取、决策支持和创意生成。
  • python学智能算法(三十六)|SVM-拉格朗日函数求解(中)-软边界
  • 算法题(183):质量检测
  • Java异常:认识异常、异常的作用、自定义异常
  • 扣证件照要点
  • 全栈:JDBC驱动版本和SQLserver版本是否有关系?怎么选择JDBC的版本号?
  • 数据结构—二叉树及gdb的应用
  • WebGIS视角下基孔肯雅热流行风险地区分类实战解析
  • 开源智能手机安全相机推荐:Snap Safe
  • Python如何将图片转换为PDF格式
  • PDF编辑工具,免费OCR识别表单