Leetcode 135. Candy

小朋友分糖果问题的算法解答
博客围绕给小朋友分糖果的问题展开。已知每个小朋友有一个数字,分糖规则是每人至少一颗,数字大的比相邻数字小的分得更多。解答时考虑数字连续下降、上升、相等及下降超范围等情形,最后给出了相应代码。

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?

Example 1:

Input: [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.

Example 2:

Input: [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
             The third child gets 1 candy because it satisfies the above two conditions.

 

题意:

给一堆小朋友分糖果,每个小孩都分配了一个数,分糖果的规则:

1.每个小朋友至少分到一颗糖

2.数字大的小朋友要比挨着他的数字小的小朋友分到更多的糖

请问至少需要多少糖果

 

解答:

首先我们需要考虑以下几种情形

1.数字连续下降的情况,那我们最少要分配(连续下降n小朋友)的方式为每次下降一个,n、n-1、n-2 .... 1,总和为 n*(n+1)/2,

在下面代码中,我们直接通过记录下降的次数来计算。

2.连续上升只需要不断将糖果数加一。

3.当前后相等时,糖果数直接降为一。        

4.当持续下降超过范围后,我们需要将之前的部分垫高

例如 [1,4,3,2,0,1]按算法可以得到这样的图,一个方格代表一块糖

第二个小朋友和第三个小朋友的关系不对(原因是下降序列长度较大,导致起始过高,这时候我们需要将之前的增长序列的最后一个垫高)

基于以上思想,可以得到如下代码。

代码:

class Solution {
     public int candy(int[] ratings) {
        if (ratings == null || ratings.length == 0) return 0;
        int total = 1, prev = 1, countDown = 0;
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] >= ratings[i-1]) {
                if (countDown > 0) {
                    total += countDown*(countDown+1)/2; // arithmetic progression
                    if (countDown >= prev) total += countDown - prev + 1; //need higher last stair of increase
                    countDown = 0;
                    prev = 1;
                }
                prev = ratings[i] == ratings[i-1] ? 1 : prev+1;
                total += prev;
            } else countDown++;
        }
        if (countDown > 0) { // if we were descending at the end
            total += countDown*(countDown+1)/2;
            if (countDown >= prev) total += countDown - prev + 1;
        }
        return total;
    }
}

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值