135. 分发糖果

1. 题目描述

LeetCode 第 135 题是“分发糖果”(Candy)。题目描述为:有 n 个孩子站成一排,每个孩子有一个评分值。你需要按照以下要求给这些孩子分发糖果:

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

求最少需要准备多少颗糖果。

2. 模式识别

本题可通过贪心算法来解决。贪心算法的核心思想是在每一步都做出当前看起来最优的选择,从而希望最终得到全局最优解。在本题中,我们可以通过两次遍历数组,分别考虑每个孩子与其左边和右边孩子的评分关系,来确定每个孩子应得的最少糖果数。

3. 考点分析

  • 贪心算法思想:理解并运用贪心策略,在局部做出最优选择以达到全局最优。
  • 数组遍历与条件判断:需要对数组进行多次遍历,并根据相邻元素的大小关系进行条件判断和更新。
  • 空间优化:在满足题目要求的前提下,考虑如何优化空间复杂度。

4. 解法

  • 两次遍历法
    • 第一次从左到右遍历数组,如果当前孩子的评分比左边孩子高,则当前孩子的糖果数比左边孩子多 1。
    • 第二次从右到左遍历数组,如果当前孩子的评分比右边孩子高,且当前孩子的糖果数不大于右边孩子的糖果数,则更新当前孩子的糖果数为右边孩子的糖果数加 1。
    • 最后将所有孩子的糖果数相加得到结果。
  • 常数空间优化法:通过一次遍历,记录上升和下降序列的长度,根据序列长度计算糖果数,可将空间复杂度优化到 O ( 1 ) O(1) O(1)

5. 最优解法(两次遍历法)的 C 语言代码

#include <stdio.h>
#include <stdlib.h>

// 计算最少需要的糖果数
// ratings: 孩子的评分数组
// ratingsSize: 孩子的数量
// 返回值: 最少需要的糖果数
int candy(int* ratings, int ratingsSize) {
    // 如果孩子数量为 0,直接返回 0
    if (ratingsSize == 0) {
        return 0;
    }
    // 用于存储每个孩子应得的糖果数,初始值都为 1
    int* candies = (int*)malloc(ratingsSize * sizeof(int));
    for (int i = 0; i < ratingsSize; i++) {
        candies[i] = 1;
    }

    // 第一次从左到右遍历数组
    // 如果当前孩子的评分比左边孩子高,则当前孩子的糖果数比左边孩子多 1
    for (int i = 1; i < ratingsSize; i++) {
        if (ratings[i] > ratings[i - 1]) {
            candies[i] = candies[i - 1] + 1;
        }
    }

    // 第二次从右到左遍历数组
    // 如果当前孩子的评分比右边孩子高,且当前孩子的糖果数不大于右边孩子的糖果数
    // 则更新当前孩子的糖果数为右边孩子的糖果数加 1
    for (int i = ratingsSize - 2; i >= 0; i--) {
        if (ratings[i] > ratings[i + 1] && candies[i] <= candies[i + 1]) {
            candies[i] = candies[i + 1] + 1;
        }
    }

    // 计算所有孩子的糖果总数
    int totalCandies = 0;
    for (int i = 0; i < ratingsSize; i++) {
        totalCandies += candies[i];
    }

    // 释放动态分配的内存
    free(candies);
    return totalCandies;
}

6. 时间复杂度和空间复杂度分析

  • 时间复杂度 O ( n ) O(n) O(n),其中 n n n 是孩子的数量。代码进行了三次遍历数组的操作,每次遍历的时间复杂度都是 O ( n ) O(n) O(n),因此总的时间复杂度为 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n),主要用于存储每个孩子应得的糖果数的数组。

你可以使用以下方式调用这个函数:

int main() {
    int ratings[] = {1, 2, 2};
    int ratingsSize = sizeof(ratings) / sizeof(ratings[0]);
    int result = candy(ratings, ratingsSize);
    printf("最少需要的糖果数: %d\n", result);
    return 0;
}

这段代码首先初始化每个孩子的糖果数为 1,然后通过两次遍历数组,根据相邻孩子的评分关系更新每个孩子的糖果数,最后将所有孩子的糖果数相加得到最少需要的糖果数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

请向我看齐

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值