【LeetCode】135. Candy

本文深入探讨了LeetCode上的Candy问题,通过两次遍历数组的贪心算法,确保每个等级高的孩子都能得到比邻居更多的糖果,同时实现了O(n)的时间复杂度。

一、问题描述

There are N children standing in a line. Each child is assigned a rating value.

You are giving candies to these children subjected to the following requirements:

  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.

What is the minimum candies you must give?

Example 1:

Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.

Example 2:

Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
The third child gets 1 candy because it satisfies the above two conditions.

二、问题分析

本周选题是LeetCode上面一道难度为Hard的135题–Candy。这道题之所以是Hard难度,并不是因为代码量大或者实现困难,而是算法很精巧。由于我是按照Tag为Greedy去检索得到的题,因此自然而然我们应该考虑如何用贪心算法去实现。

题目要求每个等级高的孩子的糖数必须必他的邻居高,却没有规定如果两个等级相同邻居的糖数是怎样的。考虑初始化所有孩子一开始都只有一颗糖,如果他比他前面的孩子等级高,那么他的糖数就定为前一个孩子的糖数+1。这样从前到后扫描一次,我们即可得到每个等级更高的孩子都比他前面孩子的糖数多。

类似,再从后面向前扫描一遍,如果前面的孩子比他后面孩子等级高,并且他的糖数不多于后面的孩子,那么我们设置他的糖数为后面孩子的糖数+1。这样从后向前扫描一遍,每个等级更高的孩子都比他后面孩子的糖数多;于此同时,这样设置并不会破坏之前从前向后扫描的逻辑(每个等级更高的孩子都比他前面孩子的糖数多)。

这样经过两次扫描,每个等级高的孩子的糖数也就比他两个邻居的都高了。因此我们也就得到了最终结果。这样的算法复杂度为O(n)(两次遍历数组即可)。

三、问题求解

针对问题分析,以下是c++源代码。

class Solution {
public:
    int candy(vector<int>& ratings) {
        int size = ratings.size();
        int result[size];
        for (int i = 0; i < size; i++) {
        	result[i] = 1;
        }
        for (int i = 1; i < size; i++) {
        	if (ratings[i] > ratings[i - 1]) {
        		result[i] = result[i - 1] + 1;
        	}
        }
        for (int i = size - 2; i >= 0; i--) {
        	if (ratings[i] > ratings[i + 1] && result[i] <= result[i + 1]) {
        		result[i] = result[i + 1] + 1;
        	}
        }
        int total = 0;
        for (int i = 0; i < size; i++) {
        	total += result[i];
        }
        return total;
    }
};
### 贪心算法在 LeetCode 上的应用 贪心算法是一种通过局部最优选择来达到全局最优解的方法。其核心思想是在每一步都做出当前状态下最好的选择,从而希望最终能够得到整体的最优解[^1]。 以下是基于 Python 的几个经典贪心算法题目及其解决方案: --- #### 题目 1: **LeetCode 455. Assign Cookies** 给定两个数组 `g` 和 `s`,别表示孩子的胃口值和饼干大小。每个孩子最多只能吃一块饼干,求最大满足的孩子数量。 ##### 解法 先对两个数组进行排序,然后从小到大配饼干给尽可能多的孩子。 ```python def findContentChildren(g, s): g.sort() s.sort() i, j = 0, 0 count = 0 while i < len(g) and j < len(s): if s[j] >= g[i]: count += 1 i += 1 j += 1 return count ``` 此方法利用了贪心策略,在每次循环中优先考虑最小需求的孩子并匹配最合适的饼干[^3]。 --- #### 题目 2: **LeetCode 135. Candy** 有 n 个小孩站在一条直线上,每个小孩有一个评值。糖果的要求是:如果某个小孩的评高于相邻的小孩,则该小孩获得更多的糖果;至少每人一颗糖果。 ##### 解法 两次遍历数组,一次从前向后,另一次从后向前,确保左右两侧的关系都被满足。 ```python def candy(ratings): n = len(ratings) candies = [1] * n for i in range(1, n): if ratings[i] > ratings[i - 1]: candies[i] = candies[i - 1] + 1 for i in range(n - 2, -1, -1): if ratings[i] > ratings[i + 1]: candies[i] = max(candies[i], candies[i + 1] + 1) return sum(candies) ``` 这种方法通过两轮扫描实现了局部最优条件下的全局最优解。 --- #### 题目 3: **LeetCode 621. Task Scheduler** 给定一组任务字符以及冷却时间 `n`,计算完成所有任务所需的最少单位时间数。 ##### 解法 统计频率最高的任务数目,并根据这些任务之间的间隔安排其他任务。 ```python from collections import Counter def leastInterval(tasks, n): task_counts = list(Counter(tasks).values()) max_freq = max(task_counts) max_count = task_counts.count(max_freq) intervals = (max_freq - 1) * (n + 1) + max_count return max(len(tasks), intervals) ``` 上述代码的关键在于理解如何合理填充高频任务之间的时间间隙。 --- #### 总结 解决贪心类问题时,通常需要明确以下几个方面: - 是否可以通过逐步优化子结构解决问题? - 如何定义“局部最优”,它是否能导向“全局最优”? 此外,清晰表达逻辑流程有助于构建完整的解决方案[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值