当前位置: 首页 > 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.lryc.cn/news/614917.html

相关文章:

  • Swift 实战:秒算两个数组的交集(LeetCode 349)
  • 海康威视摄像头实时推流到阿里云公网服务器(Windows + FFmpeg + nginx-rtmp)
  • 基于开源AI大模型、AI智能名片与S2B2C商城小程序的零售智能化升级路径研究
  • Selenium使用超全指南
  • Linux运维新手的修炼手扎之第27天
  • 【无标题】AI 赋能日常效率:实用案例与操作心得分享
  • vulhub-Beelzebub靶机
  • 【LeetCode 热题 100】(五)普通数组
  • 版本控制的详细说明介绍(已有github账号版)
  • 【数学归纳法】证明数列极限
  • 模拟人脑处理文本——从分句到分词,从段落到时间线叙事
  • 小米开源大模型 MiDashengLM-7B:不仅是“听懂”,更能“理解”声音
  • 力扣前200题字符串总结
  • Effective C++ 条款31: 将文件间的编译依存关系降至最低
  • Matlab系列(004) 一 Matlab分析正态分布(高斯分布)
  • DBSCAN聚类算法实战全解析
  • 制作 VSCode 插件
  • React Native jpush-react-native极光推送 iOS生产环境接收不到推送
  • 计算机网络:如何将/22的CIDR地址块划分为4个子网
  • 华数杯C题:可调控生物节律的LED光源研究——数学建模与Python实战
  • 2025年华数杯评审标准发布
  • 2025华数杯B题一等奖方案:网络切片无线资源管理全解析(附Python/MATLAB代码)
  • 计算机网络1-6:计算机网络体系结构
  • 4深度学习Pytorch-神经网络--损失函数(sigmoid、Tanh、ReLU、LReLu、softmax)
  • 等保测评-RabbitMQ中间件
  • 直接插入排序算法:可视化讲解与C语言实现
  • Android MediaMetadataRetriever取视频封面,Kotlin(1)
  • 记一次奇异的bug
  • 自动化一键部署 LNMP 环境
  • 【n8n教程笔记——工作流Workflow】文本课程(第二阶段)——5 自动化业务工作流——0 用例 (Use case)