135.Candy

135.Candy

题目

有N 个孩子站成一排,每个孩子被分配一个等级值。
你给这些孩子按照以下要求分糖果:
每个孩子必须至少有一个糖果。
高等级的孩子得到的糖果比相邻的孩子多。
最少给多少个糖果?

代码块

代码1:时间复杂度为O(n^2) ,不能AC。

import java.util.Arrays;

class Solution {
    public static int candy(int[] ratings) {
        int[] candies = new int[ratings.length];
        Arrays.fill(candies, 1);
        boolean flag = true;
        int sum = 0;
        while(flag){
            flag = false;
            for(int i = 0; i < candies.length; i++){
                if(i > 0 && ratings[i] < ratings[i-1] && candies[i-1] <= candies[i]){//i>0 与i<len-1弄混了,不清楚判断条件是为了保证数组不越界
                    candies[i-1] = candies[i] + 1;
                    //flag = false;
                    flag = true;
                }
                if(i < candies.length - 1 && ratings[i] < ratings[i+1] && candies[i+1] <= candies[i]){
                    candies[i+1] = candies[i] + 1;
                    //flag = false;
                    flag = true;
                }
            }

        }
        //for(int i = 0; i < candies.length; i++){
        for(int candy : candies){ //这个格式没见过
                //sum += candies[i];
            sum += candy;
            }

        return sum ;

    }
    public static void main(String[] args) {
        int[] ratings = {3,2,1,4,5,6};
        System.out.println(candy(ratings));
    }

}

代码2:时间复杂度为O(n),能够AC

class Solution {
    public int candy(int[] ratings) {

        int[] left2right = new int[ratings.length];
        int[] right2left = new int[ratings.length];
        Arrays.fill(left2right, 1);
        Arrays.fill(right2left, 1);
        int sum = 0;
        for(int i = 1; i < ratings.length ; i++){   //i的范围
            if(ratings[i] > ratings[i - 1]){
                left2right[i] = left2right[i - 1] + 1;
            }
        }
        for(int i = ratings.length - 2; i >= 0; i--){
            if(ratings[i] > ratings[i + 1]){
                right2left[i] = right2left[i + 1] + 1;
            }
        }
        for(int i = 0; i < ratings.length; i++){
            sum += Math.max(left2right[i], right2left[i]);
        }
        return sum;

    }
}

代码分析

代码#1暴力破解【时间超时】
  1. 最简单的方法是使用一维数组,candies来记录给学生的糖果。首先,给每个学生一个糖果,然后,我们开始开始从左到右扫描数组。遍历到任一元素,首先,如果当前的元素等级,ratings[i]比它前一个元素(ratings[i-1])大,并且candies[i]<=candies[i−1],则我们将candies[i]更新为 candies[i]=candies[i-1] + 1。因此,现在对于candies[i−1] 和candies[i]这两个元素糖果的分发是暂时(局部)正确的。
  2. 同样的步骤,我们来检查当前的元素级别ratings[i],假如比下一个元素等级高,ratings[i]>ratings[i+1],我们就再次更新 candies[i]=candies[i+1] + 1。我们对整个rantings数组继续这一步骤。如果在遍历过程中,candies数组中的元素不再更新了,就意味着我们达到了最后的要求。为了记录这一过程,我们使用了一个flag,如果在遍历中发生了任何更新,它将被设置为 {True}。
  3. 最后,我们将candies数组元素加起来就可以的到要求的最小糖果数了。
    时间复杂度:O(n^2) 我们需要遍历数组最多n次。
    空间复杂度: O(n) 只需要一个n长的candies数组就可以了。
代码#2 使用两个数组【AC】

此法使用两个一维数组left2right 和 right2left。
1. 用 left2right来存储当前学生所需要的分发的糖果的数量,只考虑左边的邻居。比如:假定分发规则是:一个比左边等级高的学生总比左边得到更多的糖果。
相似的,right2left用来存储只考虑右边邻居的满足要求的糖果数。假定分发规则是:一个比右边等级高的学生总比右边得到更多的糖果。
2. 为了满足要求,我们先将两个数组元素都置为一(给每个学生分发一个糖果)。然后
3. 然后根据上述规则遍历数组,先从左到右,如果当前元素的等级比左边高,我们就更新left2right数组,left2right[i] = left2right[i-1] + 1,因为在更新之前当前元素的糖果总是小于等于左边的。
4. 在前向遍历后,再来更新right2left数组, right2left[i] = right2left[i + 1] +1。
5. 在第i个位置的学生,再取两个数组中的最大值,就可以满足左右关系了。最后把他们加起来即可。

小知识

for(int candy : candies)
遍历candies数组,每次遍历的对象用candy 这个对象去接收。
相当于:

int candy=0; //用于接收index数组中的某一个对象
for(int j = 0;j<candies.length;j++){
candy = candies[j];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值