基于贪心策略的孩子糖果分发问题求解
一、问题描述 在这个问题中,有 `n` 个孩子站成一排,每个孩子都有一个对应的评分,存储在整数数组 `ratings` 中。我们需要给每个孩子分发糖果,满足以下两个条件:首先,每个孩子至少分配到 1 个糖果;其次,相邻两个孩子中评分更高的孩子会获得更多的糖果。最终,我们要计算并返回分发糖果的最少总数目。
二、解题思路 我们可以采用贪心算法来解决这个问题。从左到右遍历一次数组,再从右到左遍历一次数组,分别处理相邻孩子的评分关系,以确定每个孩子最少应得的糖果数,最后将所有孩子的糖果数相加得到最少糖果总数。 具体来说,在从左到右的遍历过程中,如果当前孩子的评分大于其左边孩子的评分,那么当前孩子的糖果数至少比左边孩子多 1;在从右到左的遍历过程中,如果当前孩子的评分大于其右边孩子的评分,且当前孩子的糖果数不大于右边孩子的糖果数,那么需要更新当前孩子的糖果数为右边孩子的糖果数加 1。这样两次遍历之后,每个孩子的糖果数都能满足相邻孩子评分的要求,并且是最少的情况。
三、代码实现 ```cpp class Solution { public: int candy(vector<int>& ratings) { int n = ratings.size(); // 初始化每个孩子至少有 1 个糖果 vector<int> candies(n, 1); // 从左到右遍历,处理相邻孩子评分关系 for (int i = 1; i < n; ++i) { if (ratings[i] > ratings[i - 1]) { candies[i] = candies[i - 1] + 1; } } // 从右到左遍历,再次处理相邻孩子评分关系并更新糖果数 for (int i = n - 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 < n; ++i) { totalCandies += candies[i]; } return totalCandies; } }; ``` 在上述代码中: 1. 首先根据孩子的数量 `n` 初始化一个 `vector` `candies`,每个元素初始化为 1,表示每个孩子至少有 1 个糖果。 2. 第一次 `for` 循环从左到右遍历 `ratings` 数组,如果当前孩子评分大于左边孩子评分,则更新当前孩子的糖果数为左边孩子糖果数加 1。 3. 第二次 `for` 循环从右到左遍历 `ratings` 数组,当当前孩子评分大于右边孩子评分且当前孩子糖果数不大于右边孩子糖果数时,更新当前孩子的糖果数为右边孩子糖果数加 1。 4. 最后遍历 `candies` 数组,将所有元素相加得到最少糖果总数并返回。
四、时间复杂度分析 从左到右遍历和从右到左遍历数组都只需要遍历一次数组,时间复杂度为 $O(n)$,其中 `n` 是孩子的数量。最后计算糖果总数的遍历也是 $O(n)$,所以总的时间复杂度仍然是 $O(n)$。
五、空间复杂度分析 代码中使用了一个与孩子数量相同大小的 `vector` 来存储每个孩子的糖果数,所以空间复杂度为 $O(n)$。可以通过一些优化手段,例如只使用常数个变量来记录当前和相邻孩子的糖果数情况,将空间复杂度优化到 $O(1)$,但这样会使代码的可读性和逻辑复杂度有所增加。 通过以上贪心算法的实现,我们可以高效地解决孩子糖果分发问题,得到最少的糖果分发总数目。在实际应用中,类似的贪心策略可以应用于很多资源分配问题,只要能够确定局部最优解能够导向全局最优解,就可以采用这种思路来简化问题的求解过程。 --- 希望这篇博客能够帮助你理解如何解决孩子糖果分发问题,如果有任何疑问或者建议,欢迎留言交流。