LeetCode-Java:135.分发糖果

文章讲述了如何使用穷举法解决孩子糖果分配问题,原始穷举法需检查前后元素,而改进版仅比较相邻元素,提高了效率。通过示例和代码解释了两种方法的工作原理和优化过程。
摘要由CSDN通过智能技术生成

文章目录

    • 题目
      • ① 穷举法,用时3ms,超过26.93%
      • ②穷举法改进,用时2ms,超过97.78%

题目

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
     第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

① 穷举法,用时3ms,超过26.93%

数组正序,当前元素和前后的元素比较,如果大则要保证比相邻的同学糖果多1个,数组逆序检查,如果当前同学的评分比相邻同学高,则保证比相邻同学糖果多1个。

注:下面的代码为了简化,设置了每个同学初始获得的糖果为0,计算完成之后再给每个同学发一个糖果,保证每人至少1个,所以candy数组并不是实际发放的糖果数目,还要在计算之后每个元素+1

问题:为什么正序之后,还要逆序检查?

答:假设没有逆序检查,用例ratings输入为[1,2,87,87,87,2,1]时,candy=[0,1,2,0,1,1,0]。当for循环运行到最后一个‘87’时,candy=[0,1,2,0,0,0,0],下一个评分为‘2’的同学,此时分配的糖果数目为0,所以最后一个‘87’分的同学满足比相邻同学的糖果多1个,分配糖果数目为1,即candy=[0,1,2,0,1,0,0]。然后运行至分数为‘2’的同学那里,按照和相邻同学对比的原则,最终可得1个糖果,因为他的糖果数目发生改变,所以之前分配给‘87’分同学的数目就少了一个,不满足原题目条件,故最后需要逆序检查。

问题:既然要检查,为什么不改成如果当前元素的糖果发生变化,就对上一个进行检查呢?

答:这个思路尝试后发现,如果当前同学的糖果增加了,上一个同学的糖果可能也会变化,上一个同学的糖果如果变化,那么上上个同学也应该检查。如此循环反复,就会变成每一次发生变化之后,就得检查前面所有的同学是否要改变,比逆序检查一次所耗费的时间更多。举个例子,ratings=[1,16,10,8,7,3,2],如果按照只检查上一次的话,最终的candy=[0,1,2,2,2,1,0],不符合题目要求。

class Solution {
    public int candy(int[] ratings) {
        int[] candy=new int[ratings.length];//数组初始所有元素为0
        int num=0;
        //数组正序,检查每个同学和相邻同学评分
        for(int i=0;i<ratings.length;i++){
            if(i!=ratings.length-1 && ratings[i]>ratings[i+1]){
                // 如果该同学比下一个同学分数高,则他的糖果要比下一个同学多1个
                candy[i]=candy[i+1]+1;
            }
            if(i!=0 && ratings[i]>ratings[i-1]){
                // 如果该同学比上一个同学分数高,则他的糖果要比下一个同学多1个
                candy[i]=candy[i-1]+1;
            }
        }
        //数组逆序,检查分配是否有误
        for(int i=ratings.length-1;i>=0;i--){
            if(i!=0 && ratings[i]>ratings[i-1] && candy[i]<=candy[i-1]){
                // 如果该同学比上一个同学分数高,并且糖果少于上一个同学,则他要比上个同学多一个
                candy[i]=candy[i-1]+1;
            }
            if(i!=ratings.length-1 && ratings[i]>ratings[i+1] && candy[i]<=candy[i+1]){
                // 如果该同学比下一个同学分数高,并且糖果少于下一个同学,则他要比下个同学多一个
                candy[i]=candy[i+1]+1;
            }
        }
        for(int j=0;j<ratings.length;j++){
            // 将数组的所有元素相加
            num+=candy[j];
        }
        return num+ratings.length;//每个同学至少一个糖果,所以返回值加上length
    }
}

②穷举法改进,用时2ms,超过97.78%

和①的区别在于,①每次循环都是和前后两个元素进行比较,②正循环的时候只和左边元素比较,倒序的时候只和右边元素比较

删掉了两个if的部分,对代码进行了简化

class Solution {
    public int candy(int[] ratings) {
        int[] candy=new int[ratings.length];
        int num=0;
        for(int i=0;i<ratings.length;i++){
            if(i!=0 && ratings[i]>ratings[i-1]){
                candy[i]=candy[i-1]+1;
            }
        }
        for(int i=ratings.length-1;i>=0;i--){
            if(i!=ratings.length-1 && ratings[i]>ratings[i+1] && candy[i]<=candy[i+1]){
                candy[i]=candy[i+1]+1;
            }
        }
        for(int j=0;j<ratings.length;j++){
            num+=candy[j];
        }
        return num+ratings.length;
    }
}
  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值