题目描述:
There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
- Each child must have at least one candy.
- Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?
分糖果的问题, 有两条规则:
- 每个孩子必须至少有一个糖果.
- 如果rating比相邻的孩子高, 那么也必须有更多的糖果. 也就是说相等的rating是没有要求的, 跟小于一样.
我所采用的思路是一种类似双指针的方法:
- 扫描一遍ratings, 找到所有小于等于相邻元素的元素的rating, 这些rating是可以直接设为1的.
- 在上一步的到的数组中每两个相邻的rating中间找到rating的最大值
- 比较这个最大值与相邻的两个最小rating的距离, 使用等差数列来算出所需要的总rating值.
对于最后一步为什么可以使用等差数列, 因为对于两个candy值为1的孩子中间的孩子, 按照索引顺序的话他们各自的candy值是先增后减的趋势, 为了保证总得candy最小每次增加或减少1是唯一方法, 是两个等差数列. 但是由于最大rating的孩子与两边candy为1的孩子的距离不同, 这两个数列也不同. 比如对于以下的ratings
[6,8,9,10,2,1]
对应的最小candy值应为:
[1,2,3,4,2,1]
左边数列是一个从左边的candy为1的孩子到rating最大的孩子共4个, 而右边则是到2就结束了. 把输入数据颠倒一下:
[1,2,10,9,8,6]
对应的结果应为:
[1,2,4,3,2,1]
数列的形式也颠倒了, 所以要根据rating最大的孩子到左右两边的距离来分别求和.
还有一些其他问题:
- 关于最左边与最右边的值, 因为他们只有一边有邻居, 所以不能像中间的节点一样计算. 我的方法是在前后各插入一个INT_MIN, 这样就可以把两端节点当作中间节点来处理了. 最后再从结果中减去.
- rating的最大值有多个. 这种情况只有一种可能, 就是两个连续的最大rating值(从我的方法来说, 其他情况都是不可能的), 由于相等的两个值没有大小要求, 因此也应该分别计算.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| class Solution { public: int candy(vector<int>& ratings) { int n = ratings.size(); if(n < 2) return 1; vector<int> oneIndex; oneIndex.push_back(-1); if(ratings[0] <= ratings[1]) oneIndex.push_back(0); for(int i = 1; i < n - 1; i++){ if(ratings[i] <= ratings[i - 1] && ratings[i] <= ratings[i + 1]) oneIndex.push_back(i); } if(ratings[n - 1] <= ratings[n - 2]) oneIndex.push_back(n - 1); oneIndex.push_back(n); int ans = oneIndex.size() - 2, i = 0; while(i < oneIndex.size()){ while(i < oneIndex.size() - 1 && oneIndex[i + 1] == oneIndex[i] + 1) i++; if(i == oneIndex.size() - 1) break; int left = oneIndex[i], right = oneIndex[i + 1]; int maxRating = INT_MIN, maxIndex; for(int j = left + 1; j < right; j++){ if(ratings[j] >= maxRating){ maxRating = ratings[j]; maxIndex = j; } } if((ratings[maxIndex - 1] == ratings[maxIndex] && maxIndex - 1 != left)){ ans += (2 + maxIndex - left) * (maxIndex - left - 1) / 2; ans += (right - maxIndex) * (3 + right - maxIndex) / 2; } else if(right - maxIndex < maxIndex - left){ ans += (3 + maxIndex - left) * (maxIndex - left) / 2; ans += (right - maxIndex - 1) * (2 + right - maxIndex) / 2; } else{ ans += (2 + maxIndex - left) * (maxIndex - left - 1) / 2; ans += (right - maxIndex) * (3 + right - maxIndex) / 2; } i++; } return ans; } };
|