赞
踩
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
先根据题意简单模拟一下解题过程,看下图,输入是每个孩子的评分,每个孩子初始都能分到一个糖果。
第一步:对于第一个位置,孩子的评分是1,比较他的左右评分,左边没有不用比较,评分比右边孩子的小,所以不用改变糖果数量,继续依次从左往右遍历:
通过分析发现,第二个位置小孩的评分比右边的小孩子低,所以先不变,但是它比左边孩子的评分高,所以糖果数要加一个,变成2。
第二步:继续遍历第三个小孩子的评分87,它和右边的孩子评分一样,所以糖果数先不变,但是它的评分又比左边孩子的高,所以糖果数也要比左边孩子的高:
第三步:继续遍历第四个孩子,它的评分和左右孩子的一样,所以糖果数不变,那么直接看第五个孩子的评分,比它右边的高,所以糖果数加一,和左边孩子一样,糖果数保持不变。
第四步:遍历到第六个孩子的评分2,它比它右边的孩子评分高,所以糖果数加一,比左边的小,加一后先保持不变:
第五步:遍历最后一个孩子的评分,它的评分比左右的都小,所以糖果数不变。至此,所有糖果分发完毕。
这里应该会注意到一个问题,就是第五个孩子的评分比第六个孩子的评分高,但是糖果数和第六个孩子是一样的,那怎么解决呢?答案就是再从左到右再遍历一遍即可。这里就不逐一展示了,当遍历到第五个孩子时,糖果数加一即可:
使用两个数组,一个数组(left2Right)记录从左往右遍历评分时糖果数的变化,一个数组(right2Lift)记录从右往左遍历评分的变化。
当从左往右遍历的时候,利用left2Right
数组记录孩子糖果数的变化,遍历每一个孩子的评分时,每个孩子只与左边的孩子的评分进行比较,如果当前孩子的评分比左边的孩子大,那么糖果数就加一。
当从右往左遍历的时候,利用right2Left
数组记录孩子糖果数的变化,遍历每一个孩子的评分时,每个孩子只与右边的孩子的评分进行比较,如果当前孩子的评分比右边的孩子大,那么糖果数就加一。
最终的糖果数统计每个孩子在两个数组left2Right
和right2Left
中的最大值就行,第一个孩子就是1,第二个孩子是2,第三个孩子是3,以此类推。最终得到:
//定义小孩子的个数 int n = ratings.length; //定义每个小孩子得到糖果的数组 int[] candies = new int[n]; //先给每个小孩子赋值一个糖果 Arrays.fill(candies,1); //使用一个变量表示糖果有变化 boolean hasChange = true; while (hasChange){ //一开始糖果数没有变化,就是false hasChange = false; //遍历每一个孩子的评分 for (int i=0; i<n; i++){ /** * 与右边孩子比较 * 三个条件:1.不是最右边的孩子。2.评分大于右边的孩子。3.糖果数小于右边的孩子 */ if (i!=n-1 && ratings[i]>ratings[i+1] && candies[i]<=candies[i+1]){ candies[i] = candies[i+1] + 1; hasChange = true; //糖果数有变化就设置为true } /** * 与左边孩子比较 * 三个条件:1.当前孩子不是最左边的孩子。2.评分大于左边孩子。3.糖果数小于等于左边孩子 */ if (i!=0 && ratings[i]>ratings[i-1] && candies[i]<=candies[i-1]){ candies[i] = candies[i-1] + 1; hasChange = true; } } } int sum = 0; //累加糖果数 for (int candy : candies){ sum += candy; } return sum;
时间复杂度是O(n2):假如说对于一个降序排列的评分,从左往右遍历每循环一次只会算对一个孩子的糖果数(可以自己试试),所以要循环n次,时间服复杂度就是O(n2)。
class Solution { public int candy(int[] ratings) { int n = ratings.length; //两个数组分别记录从左往右和从右往左遍历时的糖果数变化,初始都是1个糖果 int[] left2Right = new int[n]; Arrays.fill(left2Right,1); int[] right2Left = new int[n]; Arrays.fill(right2Left,1); //从左往右 for (int i=0; i<n; i++){ if (i!=0 && ratings[i] > ratings[i-1]){ left2Right[i] = left2Right[i-1] + 1; } } //从右往左 int sum = 0; for (int i=n-1; i>=0; i--){ if (i!=n-1 && ratings[i]>ratings[i+1]){ right2Left[i] = right2Left[i+1] + 1; } //将两个数组中的最大值累加就是最大糖果数 sum += Math.max(left2Right[i], right2Left[i]); } return sum; } }
时间复杂度是O(n),因为只经历了两次遍历
空间复杂度O(n),因为申请了两个数组(精确一点应该是2n)
只用一个数组,优化空间,使用一个变量来记录从右往左遍历时的值
class Solution { public int candy(int[] ratings) { int n = ratings.length; //使用一个数组记录从左往右的糖果数变化,初始都是1个糖果 int[] left2Right = new int[n]; Arrays.fill(left2Right,1); //从左往右 for (int i=0; i<n; i++){ if (i!=0 && ratings[i] > ratings[i-1]){ left2Right[i] = left2Right[i-1] + 1; } } //从右往左 int sum = 0; //使用一个变量来存储从右往左遍历时的糖果数量变化 int right = 0; for (int i=n-1; i>=0; i--){ if (i!=n-1 && ratings[i]>ratings[i+1]){ right++; }else { right = 1; //不符合if中的条件,糖果数重新置为1 } //将两个数组中的最大值累加就是最大糖果数 sum += Math.max(left2Right[i], right); } return sum; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。