NO.135 分发糖果 困难
思路一:贪心算法 分发糖果的规则:
- 如果[i]比[i-1]分高即右边的大于左边的,则[i]的糖果要比[i-1]的多,但是为了使总糖果数最少,所以给[i]增加最小的增量 +1。
- 同理,如果[i]比[i+1]分高即左边的大于右边的,则[i]的糖果要比[i+1]的多,但是为了使总糖果数最少,所以给[i]增加最小的增量 +1。
只有当必须给某个孩子增加糖果时(左大于右/右大于左),才给这个孩子增加一个最小的增量 +1。
开始,每个人都分配最少的糖果 1 个。先从左向右遍历孩子的分数,如果[i]>[i-1]
则使[i]的糖果=[i-1]的糖果+1
,并将这一过程中每个人分配的糖果数量记录在 left 数组中。
同理,再从逆序遍历孩子的分数,如果[i]>[i+1]
则使[i]的糖果=[i+1]的糖果+1
,并将这一过程中每个人分配的糖果数量记录在 right 数组中。
最后,计算总糖果时,每个人应得的糖果数是取 left 或 right 中对应的最大糖果数,这样才能同时满足开头的两个规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public int candy(int[] ratings) { int[] left = new int[ratings.length]; int[] right = new int[ratings.length]; Arrays.fill(left, 1); Arrays.fill(right, 1); for (int i = 1; i < ratings.length; i++) { if (ratings[i] > ratings[i - 1]) left[i] = left[i - 1] + 1; } for (int i = ratings.length - 2; i >= 0; i--) { if (ratings[i] > ratings[i + 1]) right[i] = right[i + 1] + 1; } int sum = 0; for (int i = 0; i < ratings.length; i++) { sum += Math.max(left[i], right[i]); } return sum; }
|
时间复杂度:O(n) 五次遍历。
空间复杂度:O(n) 两个数组记录,两个规则下的分配方案。
这个思路还能再优化一下,只用一个数组 candies 。第一次遍历不变,第二次遍历时如果ratings[i] > ratings[i + 1]
不立刻更新,如果此时 candies[i] 已经大于 candies[i+1]则不需要更新,否则更新为 candies[i+1]+1,并且到此已经完成了对 candies[i] 的分配,直接统计入结果中即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public int candy(int[] ratings) { int[] candies = new int[ratings.length]; candies[0] = 1; for (int i = 1; i < ratings.length; i++) { if (ratings[i] > ratings[i - 1]) candies[i] = candies[i - 1] + 1; else candies[i] = 1; } int sum = candies[candies.length - 1]; for (int i = ratings.length - 2; i >= 0; i--) { if (ratings[i] > ratings[i + 1]) candies[i] = Math.max(candies[i], candies[i + 1] + 1); sum += candies[i]; } return sum; }
|
时间复杂度:O(n) 两次遍历。
空间复杂度:O(n) 一个数组记录。
本人菜鸟,有错误请告知,感激不尽!
更多题解和源码:github