LeetCode-Java:135.分发糖果

发布于:2024-04-04 ⋅ 阅读:(114) ⋅ 点赞:(0)

文章目录

    • 题目
      • ① 穷举法,用时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;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到