Leetcode 135 糖果分配

164 阅读1分钟

135. 糖果分配

题目描述

一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果;所有孩子至少要有一个糖果。求解最少需要多少个糖果。

输入输出样例

输入是一个数组,表示孩子的评分。输出是最少糖果的数量。

Input: [1,0,2] Output: 5 在这个样例中,最少的糖果分法是 [2,1,2]。

思考地图

1 首先想到的是利用 dp, dp 表示到 i 位置的时候前面每个位置分配糖果的多少,当到 i+1 的位置时候,判断 input[i+1]和 input[i]的关系,如果 input[i+1]>input[i],则 dp[i+1] = dp[i]+1;如果 input[i+1]===input[i],dp[i+1] = dp[i],如果是 input[i+1]< input[i],dp[i+1] = dp[i]-1,如果 dp[i] === 1,则 dp[i] = dp[i]+1,然后依次重新设置 dp 的糖果分配,但是处理逻辑有问题。

2 运用贪心策略,需要简单的两次遍历即可:把所有孩子的糖果数初始化为 1; 先从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1; 再从右往左遍历一遍,如果左边孩子的评分比右边的高,且左边孩子当前的糖果数不大于右边孩子的糖果数,则左边孩子的糖果数更新为右边孩子的糖果数加 1。通过这两次遍历, 分配的糖果就可以满足题目要求了。这里的贪心策略即为,在每次遍历中,只考虑并更新相邻一 侧的大小关系。 在样例中,我们初始化糖果分配为 [1,1,1],第一次遍历更新后的结果为 [1,1,2],第二次遍历 更新后的结果为 [2,1,2]。

但是这种解法是如何想到呢?

可以分开步骤完成的,要分开完成,我思考的地方在于希望一步把所有的东西全部完成,其实可以分开,一步一步来完成。

完成一步,再完成下一步,这样逻辑就会简单很多。

/**
 * @param {number[]} ratings
 * @return {number}
 */
export default (ratings) => {
  if (!ratings || ratings.length === 0) return 0;
  const len = ratings.length;
  const dp = new Array(len).fill(1);

  for (let i = 1; i < len; i++) {
    if (ratings[i] > ratings[i - 1] && dp[i] <= dp[i - 1]) {
      dp[i] = dp[i - 1] + 1;
    }
  }

  for (let j = len - 2; j >= 0; j--) {
    if (ratings[j] > ratings[j + 1] && dp[j] <= dp[j + 1]) {
      dp[j] = dp[j + 1] + 1;
    }
  }

  return dp.reduce((a, b) => a + b);
};

时间复杂度 O(n), 空间复杂度 O(n)