leetcode hard模式专杀之135. Candy

来源:互联网 发布:win7网络图标灰色 编辑:程序博客网 时间:2024/06/05 09:07

这题大概思路出来大概十来分钟,不过做到通过oj却花了几个小时,主要是一些情况没有考虑完整,首先在纸上画一划,看看如果人去做这件事,会怎么做,画了几遍之后,可以得出一个大概都结论,例如ratings序列是[1,2,3,7,5,6,9,2,1],首先第一个位置的孩子得到1个糖果,rating值等于5的孩子得到1个糖果, 然后最后一个孩子得到一个糖果,然后其他位置的孩子,从这几个位置推导出来即可,那么两个问题来了, 第一,这三个位置如何得到呢?如果把这个几个值连一条曲线,会发现这几个点都在local minimum的位置,所以只要先找出每个localMinum的位置,这些位置的孩子就可以确定得到1个糖果,计算localMinimum位置时,注意一串相等的数字的情况,例如【5,4,4,4,4,6】这么一串数字,第一个4毫无疑问是localMin,那么第二个4计算的时候只要看到前一个4已经是localMin,就不需要再做运算了,直接可以判定为也是localMin,这样可以节约计算时间,然后再逐个想办法,把每两个localMinimum之间的数字填充正确,别忘了开头和结尾两个位置的特殊情况。第二个问题是,填充的原则是什么。两个localMininum之间可能有几种情况,例如假设给定两个点1,1,要在这两个数之间填充比1大的数字,可能出现三种情况,单调递增,如【2,3,4】,单调递减,如【5,4,3】,先递增后递减【3,5,4】,还有可能出现有连续相同数字的情况【3,4,4,5】,【3,4,5,5,4】等等。怎么统一处理呢?想到一种思路,对所有localminimum切割成的一段段位置,分别做如下处理:两个循环,第一个从左端点开始一路向右遍历,直到不再递增(相等也算递增吧),第二个同样反过来从右端点一路向左遍历,直到不再递增,遍历的时候这样设值:如果大于前一个数q,则设置为q处count值+1或这该位置已有值二者之间的大者,为什么是这样,可以假设有两个localMin位置之间是这样一个序列1,3,8,7,6,5,4,1,8这个位置如果从左往右看,需要该位置的糖果值是3, 而如果从右往左看,需要的糖果数是6,到底选3还是选6呢?当然是选大的,也就是6才行。如果等于前一个数字,则在1和该位置已有值之间去大者,为什么会是跟1比?因为如果有3,4,4,4,3这样一个序列,则中间这个4这个位置的值完全可以设为1,也就是我们可以设计一种原则,只要跟前一个数比rating值相等,则这个位置可以先试着放1,除非从另一侧的遍历时要求这个位置有更大的值(这也是为什么要用max函数的原因)。思路大概如此,代码如下:

public class Solution {        public static void setNeighbour(int[] ratings, int[] counts, int start, int end) {int len = ratings.length;if(end-start<=1) {return;}if(end-start==2) {counts[start+1]=2;}else {//left to rightint i = start+1;while(i<=len-1 && (i==0 || ratings[i]>=ratings[i-1])) {if(i==0) {counts[0] = 1;}else {if(ratings[i]>ratings[i-1]) {counts[i]=Math.max(counts[i], counts[i-1]+1);}else {//equalcounts[i]=Math.max(counts[i], 1);}}i++;}//right to leftint j = end-1;while(j>=0 && (j==len-1 || ratings[j]>=ratings[j+1])) {if(j==len-1) {counts[j]=1;}else {if(ratings[j]>ratings[j+1]) {counts[j]=Math.max(counts[j+1]+1,counts[j]);}else {//equalcounts[j] = Math.max(counts[j], 1);}}j--;}}}        public static boolean localMin(int[] ratings, int index) {boolean leftBigger = false;boolean rightBigger = false;int len = ratings.length;int i = index - 1;while(i>=0 && ratings[i]==ratings[index]) {i--;}if(i<0) {leftBigger = true;}else if(ratings[i] > ratings[index]) {leftBigger = true;}int j = index + 1;while(j < len && ratings[j]==ratings[index]) {j++;}if(j>=len) {rightBigger = true;}else if(ratings[j]>ratings[index]) {rightBigger = true;}return leftBigger && rightBigger;}        public int candy(int[] ratings) {        int len = ratings.length;BitSet bs = new BitSet();boolean leftBigger = true;for(int i = 0 ; i < len; i++) {if(i>0 && ratings[i] == ratings[i-1] &&bs.get(i-1)) {bs.set(i);}else if(localMin(ratings, i)) {bs.set(i);}}        System.out.println("Input is:" + Arrays.toString(ratings));System.out.println("Bit set is:" + bs);int[] counts = new int[len];//set counts startint prevLocalMinPos = -1;for(int i = 0; i< bs.length(); i++) {if(bs.get(i)) {counts[i] = 1;setNeighbour(ratings, counts, prevLocalMinPos, i);prevLocalMinPos = i;}}if(prevLocalMinPos < len-1) {for(int i = prevLocalMinPos+1; i< len; i++) {if(ratings[i]>ratings[i-1]) {counts[i] = counts[i-1]+1;}else {// equalscounts[i] = 1;}}}//set counts endint result = 0;for(int i = 0 ; i<counts.length; i++) {result += counts[i];}System.out.println("Counts is:" + Arrays.toString(counts));return result;    }}


原创粉丝点击