|
| 1 | +# 135. Candy |
| 2 | + |
| 3 | +**<font color=red>难度: Hard</font>** |
| 4 | + |
| 5 | +## 刷题内容 |
| 6 | + |
| 7 | +> 原题连接 |
| 8 | +
|
| 9 | +* https://leetcode.com/problems/candy/ |
| 10 | + |
| 11 | +> 内容描述 |
| 12 | +
|
| 13 | +``` |
| 14 | +
|
| 15 | +There are N children standing in a line. Each child is assigned a rating value. |
| 16 | +
|
| 17 | +You are giving candies to these children subjected to the following requirements: |
| 18 | +
|
| 19 | +Each child must have at least one candy. |
| 20 | +Children with a higher rating get more candies than their neighbors. |
| 21 | +What is the minimum candies you must give? |
| 22 | +
|
| 23 | +Example 1: |
| 24 | +
|
| 25 | +Input: [1,0,2] |
| 26 | +Output: 5 |
| 27 | +Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively. |
| 28 | +Example 2: |
| 29 | +
|
| 30 | +Input: [1,2,2] |
| 31 | +Output: 4 |
| 32 | +Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively. |
| 33 | + The third child gets 1 candy because it satisfies the above two conditions. |
| 34 | +``` |
| 35 | + |
| 36 | +## 解题方案 |
| 37 | + |
| 38 | +> 思路 1 |
| 39 | +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +- 首先我们从左往右边看,如果当前child的rating比它左边child的rating大,那么当前child分的candy肯定要比它左边多1 |
| 44 | +- 然后从右往左边看,如果当前child的rating比它右边child的rating大,那么当前child分的candy肯定要比它右边多1 |
| 45 | + |
| 46 | +我们知道这两种情况我们都必须满足,所以最后我们取两者中的大者(这样才能同时满足两种情况),beats 24.83% |
| 47 | + |
| 48 | +```python |
| 49 | +class Solution: |
| 50 | + def candy(self, ratings): |
| 51 | + """ |
| 52 | + :type ratings: List[int] |
| 53 | + :rtype: int |
| 54 | + """ |
| 55 | + left2right = [1] * len(ratings) |
| 56 | + right2left = [1] * len(ratings) |
| 57 | + for i in range(1, len(ratings)): |
| 58 | + if ratings[i] > ratings[i-1]: |
| 59 | + left2right[i] = left2right[i-1] + 1 |
| 60 | + for i in range(len(ratings)-2, -1, -1): |
| 61 | + if ratings[i] > ratings[i+1]: |
| 62 | + right2left[i] = right2left[i+1] + 1 |
| 63 | + res = 0 |
| 64 | + for i in range(len(ratings)): |
| 65 | + res += max(left2right[i], right2left[i]) |
| 66 | + return res |
| 67 | +``` |
| 68 | + |
| 69 | +> 思路 2 |
| 70 | +******- 时间复杂度: O(N)******- 空间复杂度: O(N)****** |
| 71 | + |
| 72 | +刚才用了2个array,其实我们可以只用一个array, beats 28.77% |
| 73 | + |
| 74 | +```python |
| 75 | +class Solution: |
| 76 | + def candy(self, ratings): |
| 77 | + """ |
| 78 | + :type ratings: List[int] |
| 79 | + :rtype: int |
| 80 | + """ |
| 81 | + res = [1] * len(ratings) # also compatable with [] input |
| 82 | + # left scan |
| 83 | + for i in range(1, len(ratings)): |
| 84 | + if ratings[i] > ratings[i-1]: |
| 85 | + res[i] = res[i-1] + 1 |
| 86 | + # right scan |
| 87 | + for i in range(len(ratings)-2, -1, -1): |
| 88 | + if ratings[i] > ratings[i+1]: |
| 89 | + res[i] = max(res[i+1]+1, res[i]) |
| 90 | + return sum(res) |
| 91 | +``` |
| 92 | + |
| 93 | + |
| 94 | +> 思路 3 |
| 95 | +******- 时间复杂度: O(N)******- 空间复杂度: O(1)****** |
| 96 | + |
| 97 | +其实我们还有另外一种思路,可以将空间降到O(1) |
| 98 | + |
| 99 | +假设: |
| 100 | +``` |
| 101 | +input: [2, 4, 6, 8, 7, 6, 5, 4, 3, 2, 7, 8, 9, 8, 7, 6, 5, 4, 3] |
| 102 | +index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19] |
| 103 | +
|
| 104 | +``` |
| 105 | + |
| 106 | +我们先直接给第一个孩子1颗candy,然后继续往下遍历,我们发现第2个孩子的rating比第一个孩子的多,于是我们给第二个孩子2颗candy, |
| 107 | +以此类推,第3个孩子3颗candy,第4个孩子4颗candy,这时候我们发现第5个孩子的rating比第4个孩子的rating要小, |
| 108 | +所以第5个孩子的candy肯定要比第4个孩子的少才行,但是不能直接给第5个孩子1颗candy这么简单,因为说不定后面孩子的rating比第5个孩子更小呢? |
| 109 | +如果第5个孩子只有1颗candy,后面的孩子岂不是没有candy了?这不符合题目要求,所以我们暂时继续走下去,我们发现一共降序走了6步,此时来到了第11个孩子, |
| 110 | +rating终于又变成升序了,这时候我们知道了,第5个孩子最少需要给6颗candy了,然后第6,7,8,9,10个孩子依次给5,4,3,2,1颗candy,总数就是6*(1+6)/2 |
| 111 | +但是问题来了,第5个孩子给了6颗candy,第4个孩子应该要比第5个孩子的candy更多呀, 于是我们补给第4个孩子3颗candy,此时第4个孩子有7颗candy |
| 112 | +(比第5个孩子的6颗多,符合题目要求)。继续走下去,第11个孩子给2颗candy,第12个孩子给3颗candy,第13个孩子给4颗candy,接下来又是降序了, |
| 113 | +又是降序走了6步,一样的原理,第14,15,16,17,18,19个孩子分别给6,5,4,3,2,1颗candy,发现第13个孩子需要补3颗candy(现在7颗candy) |
| 114 | + |
| 115 | +于是我们的candy的总和为 |
| 116 | + |
| 117 | +``` |
| 118 | +input: [2, 4, 6, 8, 7, 6, 5, 4, 3, 2, 7, 8, 9, 8, 7, 6, 5, 4, 3] |
| 119 | +candy: [1, 2, 3, 7, 6, 5, 4, 3, 2, 1, 2, 3, 7, 6, 5, 4, 3, 2, 1] |
| 120 | +index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19] |
| 121 | +
|
| 122 | +一共67颗candy |
| 123 | +``` |
| 124 | + |
| 125 | +编码实现, beats 59.40% |
| 126 | + |
| 127 | +```python |
| 128 | +class Solution: |
| 129 | + def candy(self, ratings): |
| 130 | + """ |
| 131 | + :type ratings: List[int] |
| 132 | + :rtype: int |
| 133 | + """ |
| 134 | + if not ratings: |
| 135 | + return 0 |
| 136 | + res, prev, desc_cnt = 1, 1, 0 |
| 137 | + for i in range(1, len(ratings)): |
| 138 | + if ratings[i] >= ratings[i-1]: |
| 139 | + if desc_cnt > 0: |
| 140 | + res += desc_cnt * (desc_cnt + 1) / 2 # arithmetic progression |
| 141 | + if desc_cnt >= prev: |
| 142 | + res += desc_cnt - prev + 1 |
| 143 | + desc_cnt = 0 |
| 144 | + prev = 1 |
| 145 | + # 当前child的rating和它左边child的rating一样,直接给1颗candy就满足了,否则需要给prev+1颗candy |
| 146 | + prev = 1 if ratings[i] == ratings[i-1] else prev + 1 |
| 147 | + res += prev |
| 148 | + else: |
| 149 | + desc_cnt += 1 |
| 150 | + if desc_cnt > 0: # if we were descending at the end |
| 151 | + res += desc_cnt * (desc_cnt + 1) / 2 # arithmetic progression |
| 152 | + if desc_cnt >= prev: |
| 153 | + res += desc_cnt - prev + 1 |
| 154 | + return int(res) |
| 155 | +``` |
| 156 | + |
| 157 | + |
| 158 | + |
| 159 | + |
| 160 | + |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | + |
| 167 | + |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | + |
| 191 | + |
0 commit comments