【题目】
一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:
1、每个孩子不管得分多少,起码分到1个糖果
2、任意两个相邻的孩子之间,得分较多的孩子必须多拿一些糖果
给定一个数组arr代表得分数组,请返回最少需要多少糖果。
例如:arr = [1,2,2],糖果分配[1,2,1],即可满足要求且数量最少,所以返回4.
【进阶题目】
原题目中的两个规则不变,再加一条规则:
3、任意两个相邻的孩子之间如果得分相同,糖果数必须相同
给定一个数组arr代表得分数组,返回最少需要多少糖果。
例如:arr = [1,2,2],糖果分配[1,2,2],即可满足要求且数量最少,所以返回5.
【要求】
原文题和进阶问题的时间复杂度都为O(N),空间复杂度O(1)。
【基本思路】
原问题。首先引入左坡和右坡的概念,从左到右依次遍历数组,值递增的部分为左坡,递减的部分为右坡。定义了左坡和右坡后,整个数组就可以分解成很多对左坡和右坡,挨个计算每对左坡和右坡即可。
假设数组为[1,4,5,9,3,2],左坡和右坡分别是[1,4,5,9],[9,3,2]。对左坡来说,从左到右糖果的分配为[1,2,3,4],对右坡来说,糖果的分配为[3,2,1],但是两种分配方式对9这个坡顶的分配是不同的,如何决定?哪个坡更高,就按哪个坡来分配。因为左坡和右坡都是严格的递增和递减,不存在相同的数值,所以,坡的高度就是各自序列的长度。很明显左坡的高度大于右坡的高度(4 > 3)。所以坡顶的分配按照左坡来,最终的分配为[1,2,3,4,2,1]。
#python3.5
def candy1(arr):
def nextMinIndex(arr, start):
for i in range(start, len(arr)-1):
if arr[i+1] >= arr[i]:
return i
return len(arr) - 1
def rightCands(left, right):
n = right - left + 1
return n * (n+1) // 2
if arr == None or len(arr) == 0:
return 0
index = nextMinIndex(arr, 0)
res = rightCands(0, index)
index += 1
lbase = 1
while index != len(arr):
if arr[index] > arr[index-1]:
lbase += 1
res += lbase
index += 1
elif arr[index] < arr[index-1]:
next = nextMinIndex(arr, index-1)
res += rightCands(index-1, next)
rbase = next - index + 2
res -= rbase if rbase < lbase else lbase
lbase = 1
index = next + 1
else:
res += 1
lbase = 1
index += 1
return res
进阶问题。针对新规则,需要对左坡和右坡重新定义。从左到右依次遍历数组,值不递减的部分为左坡,不递增的部分为右坡。比如,[1,2,2,1],左坡为[1,2,2],右坡为[2,1]。
假设数组为[0,1,2,3,3,3,2,2,2,2,2,1,1],左坡和右坡,分别是[0,1,2,3,3,3],[3,2,2,2,2,2,1,1]。对左坡来说,从左到右糖果的分配为[1,2,3,4,4,4],对右坡来说,糖果的分配为[3,2,2,2,2,2,1],但是两种分配方式对[3,3,3]这三个坡顶的分配还是不同的,如何决定?还是根据坡的高度,哪个坡更高,就按哪个坡来分配,因为左坡和右坡不是严格的递增和递减,可能存在相同的数值,所以,坡的高度不能再通过序列长度来计算(具体做法见如下代码) 。很明显左坡的高度大于右坡的高度(4 > 3)。所以坡顶的分配按照左坡来,最终的分配为[1,2,3,4,4,4,2,2,2,2,2,1,1]。
def candy2(arr):
def nextMinIndex(arr, start):
for i in range(start, len(arr)-1):
if arr[i] < arr[i+1]:
return i
return len(arr) - 1
def rightCandsAndBase(arr, left, right):
res = 1
base = 1
for i in range(right-1, left-1, -1):
if arr[i] == arr[i+1]:
res += base
else:
base += 1
res += base
return res, base
if arr == None or len(arr) == 0:
return 0
index = nextMinIndex(arr, 0)
res, s = rightCandsAndBase(arr, 0, index)
index += 1
lbase = 1
same = 1
while index != len(arr):
if arr[index] > arr[index-1]:
lbase += 1
res += lbase
index += 1
elif arr[index] == arr[index-1]:
res += lbase
same += 1
index += 1
else:
next = nextMinIndex(arr, index-1)
num, rbase = rightCandsAndBase(arr, index-1, next)
if rbase < lbase:
res += num - rbase
else:
res += num - rbase + rbase * same - same * lbase
index = next + 1
same = 1
lbase = 1
return res