您的位置:首页 > 其它

leetcode hard模式专杀之135. Candy

2017-08-06 15:31 288 查看
这题大概思路出来大概十来分钟,不过做到通过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 right
int 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 {
//equal
counts[i]=Math.max(counts[i], 1);
}
}
i++;
}
//right to left
int 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 {
//equal
counts[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 start
int 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 {
// equals
counts[i] = 1;
}

}
}
//set counts end

int result = 0;
for(int i = 0 ; i<counts.length; i++) {
result += counts[i];
}

System.out.println("Counts is:" + Arrays.toString(counts));

return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: