其他题目---分糖果问题

【题目】

  一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:
  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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值