0135. 分发糖果

题目链接

135. 分发糖果 - 力扣(LeetCode)

题目描述

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

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

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

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

题目示例

示例 1 :

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

示例 2 :

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

解题思路

本题要求在满足两个条件的前提下,分配最少数量的糖果:

  1. 每个孩子至少一颗糖果。
  2. 评分高的孩子比相邻评分低的孩子获得更多糖果。

这意味着对于任何一个孩子 i,他获得的糖果数量 candy[i] 必须满足:

  • 如果 ratings[i] > ratings[i-1],则 candy[i] > candy[i-1]
  • 如果 ratings[i] > ratings[i+1],则 candy[i] > candy[i+1]

为了满足这些条件,同时使总糖果数最少,我们可以采用两次遍历的策略:

  1. 第一次遍历(从左向右):
    • 我们首先满足每个孩子相对于其左侧邻居的条件。
    • 创建一个 left 数组,left[i] 表示在只考虑左侧邻居的情况下,孩子 i 应得的糖果数。
    • 初始化 left 数组所有元素为 1 (每个孩子至少一颗糖果)。
    • 从索引 1 开始遍历到 n-1
      • 如果 ratings[i] > ratings[i-1],则 left[i] = left[i-1] + 1。这意味着当前孩子比左侧邻居多一颗糖果。
      • 否则 (ratings[i] <= ratings[i-1]),left[i] 保持为 1 (因为他不需要比左边多,所以最少是1颗)。
  2. 第二次遍历(从右向左):
    • 接下来,我们满足每个孩子相对于其右侧邻居的条件。
    • 创建一个 right 数组 (或者直接在 count 中累加并处理 right 逻辑),right[i] 表示在只考虑右侧邻居的情况下,孩子 i 应得的糖果数。
    • 初始化 right 数组所有元素为 1
    • 从索引 n-2 开始遍历到 0
      • 如果 ratings[i] > ratings[i+1],则 right[i] = right[i+1] + 1。这意味着当前孩子比右侧邻居多一颗糖果。
      • 否则 (ratings[i] <= ratings[i+1]),right[i] 保持为 1
    • 合并结果: 对于每个孩子 i,他最终应得的糖果数是 max(left[i], right[i])。这是因为 left[i] 确保了对左侧邻居的条件满足,right[i] 确保了对右侧邻居的条件满足。取两者最大值可以同时满足这两个独立的条件,并且由于我们是基于"最少一颗"和"比邻居多一颗"递增的,所以取最大值是满足所有条件所需的最小数量。
    • 在第二次遍历中,我们将 max(left[i], right[i]) 累加到总数 count 中。需要注意的是,count 初始值是 left[n-1],这是因为最后一个孩子 n-1 没有右邻居,所以它的糖果数就是 left[n-1](或者说 max(left[n-1], right[n-1]) 也是 left[n-1],因为 right[n-1] 始终为 1)。

题解代码

java 复制代码
import java.util.Arrays; // 导入 Arrays 工具类,用于数组填充

class Solution {
    /**
     * 计算分发糖果的总数,满足以下条件:
     * 1. 每个孩子至少分得一颗糖果。
     * 2. 评分较高的孩子比相邻评分较低的孩子获得更多的糖果。
     *
     * @param ratings 一个整数数组,表示每个孩子的评分。
     * @return 分发糖果的总数。
     */
    public int candy(int[] ratings) {
        int n = ratings.length; // 获取孩子的总人数
        // 如果没有孩子,则不需要分发糖果
        if (n == 0) {
            return 0;
        }
        
        // left 数组:从左向右遍历,记录每个孩子相对于其左侧邻居应得的糖果数。
        // 例如,如果 ratings[i] > ratings[i-1],则 left[i] = left[i-1] + 1。
        int[] left = new int[n];
        // right 数组:从右向左遍历,记录每个孩子相对于其右侧邻居应得的糖果数。
        // 例如,如果 ratings[i] > ratings[i+1],则 right[i] = right[i+1] + 1。
        int[] right = new int[n];
        
        // 初始化:每个孩子至少分得一颗糖果,所以初始都设为1。
        Arrays.fill(left, 1);
        Arrays.fill(right, 1);
        
        // 第一次遍历:从左向右,处理"左邻居"关系
        // 遍历从第二个孩子开始 (索引1),因为第一个孩子 (索引0) 没有左邻居。
        for(int i = 1; i < n; i++) {
            // 如果当前孩子的评分高于其左侧邻居的评分
            if(ratings[i] > ratings[i - 1]) {
                // 则当前孩子比左侧邻居多一颗糖果
                left[i] = left[i - 1] + 1;
            }
        }
        
        // 初始化总糖果数。
        // 最后一个孩子的糖果数,只受左侧规则(left[n-1])影响,因为其没有右邻居需要比较。
        // 或者说,right[n-1] 肯定是1,所以 Math.max(left[n-1], right[n-1]) 就是 left[n-1]。
        int count = left[n - 1]; 
        
        // 第二次遍历:从右向左,处理"右邻居"关系,并累加最终结果
        // 遍历从倒数第二个孩子开始 (索引 n-2),因为倒数第一个孩子 (索引 n-1) 已在上面处理。
        for(int i = n - 2; i >= 0; i--) {
            // 如果当前孩子的评分高于其右侧邻居的评分
            if(ratings[i] > ratings[i + 1]) {
                // 则当前孩子比右侧邻居多一颗糖果
                right[i] = right[i + 1] + 1;
            }
            // 最终每个孩子应得的糖果数,是满足左右两边条件的最大值。
            // 例如,如果孩子A评分比左边B高,left[A]=left[B]+1。
            // 如果孩子A评分比右边C高,right[A]=right[C]+1。
            // 那么A最终应得的糖果数是 max(left[A], right[A]),以同时满足两边要求。
            count += Math.max(left[i], right[i]);
        }
        
        return count; // 返回总的糖果数
    }
}

复杂度分析

假设 n 是孩子的数量(即 ratings.length)。

  1. 时间复杂度:
    • 初始化 leftright 数组:O(n) (使用 Arrays.fill)。
    • 第一次遍历(从左向右):O(n),遍历 n-1 次。
    • 第二次遍历(从右向左):O(n),遍历 n-1 次。
    • 总的时间复杂度是所有这些步骤的总和,即 O(n) + O(n) + O(n) = O(n)
  2. 空间复杂度:
    • left 数组:O(n)
    • right 数组:O(n)
    • 其他变量 (n, i, count):O(1)
    • 总的空间复杂度是 O(n) + O(n) = O(n)
相关推荐
vivo互联网技术16 小时前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦17 小时前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户4978630507321 小时前
(一)小红的数组操作
算法·编程语言
怕浪猫1 天前
Electron 系列文章封面图
算法·架构·前端框架
徐小夕1 天前
JitWord 3.0 正式发布,高精度Word异构解析+复杂组件兼容,打造web端协同Word编辑器
前端·vue.js·算法
通信小呆呆2 天前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
benben0442 天前
强化学习之DQN算法族(基于gymnasium开发)
算法
何以解忧,唯有..2 天前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang