135.分发糖果(困难)

1. 题目描述

题目中转:135.分发糖果

在这里插入图片描述

2.详细题解

  1. 方法一谈:贪心算法:遍历两轮

    分糖果:每个孩子有一个分数,相邻的孩子高分的分得更多糖果,要求最少准备多少糖果数能满足要求。即然要求最少,那就只分满足条件的最低数量即可,即贪心的少,相邻的如果分数更高,则在满足条件下仅比低分的孩子多1个即可*,但需要注意的是,每个孩子都有一个左邻和右邻孩子(两端除外),且注意分数相同的情况下,则只分配1颗的情况也是满足题目要求的,现在总结规则,如果比相邻分数高,则至少大1,如果比左右邻的孩子都大,则应该至少是左右孩子分配数最大值+1,如果不是最大值,则不满足条件2,例如 [ 3 , 4 , 5 , 0 ] [3,4,5,0] [3,4,5,0],此时对于第二个孩子分配2颗,第四个孩子分配1颗,对于第三个孩子应该分配3颗而不是2颗才能满足条件。
  比如分数 [ 1 , 2 , 3 ] [1,2,3] [1,2,3]
,从左右至右*第一个孩子分配1颗,第二个孩子分更高则分配2颗,第三个孩子分比第二个孩子分高,则分配3颗;
  但对于分数 [ 3 , 2 , 1 ] [3,2,1] [3,2,1],从左至右第一个孩子分配1颗,第二个孩子分低,则应该比第1个孩子的数量小,但至少为1,此时就需要重新给第一个孩子分配数量,但如果从右至左分配呢,第三个孩子分配1颗,第二个孩子分高分配2颗,第一个孩子分配3颗。
  通过上面的例子可以发现,针对递增或者递减的情况,分别从不同的方向遍历计算即可,但既有递增又有递减混合的分数该如何分配呢?那就两个方向各进行一次遍历,现在闭上眼睛思考下,从左至右可以解决递增的分数,从右至左可以解决递减的分数,二合一岂不是都解决了呢?好像挺有道理!
  例如对于分数 [ 1 , 2 , 3 , 4 , 5 , 3 , 2 , 1 ] [1,2,3,4,5,3,2,1] [1,2,3,4,5,3,2,1]首先从左至右则分配糖数量,如果当前分数大于前一个分数,则分配糖数加1,否则为1,那么分配结果为 [ 1 , 2 , 3 , 4 , 5 , 1 , 1 , 1 ] [1,2,3,4,5,1,1,1] [1,2,3,4,5,1,1,1],此时解决了递增分数的分配情况;其次,现在从右至左则分配糖数量,同理,分配结果为 [ 1 , 2 , 3 , 4 , 5 , 3 , 2 , 1 ] [1,2,3,4,5,3,2,1] [1,2,3,4,5,3,2,1],其中需要注意的时,从右至左分配数,对于分数为5的孩子的糖数应该大于其右边分数为3的孩子,此时即分配4颗糖即可,但在从左至右时,其糖数应该大于左边分数为4的孩子,即分配5颗,因为需要同时满足二者条件,所以取最大值5颗。
2. 方法二:遍历一轮

建议掌握方法一即可,相对比较直观一点,符合我们的思考认知

  方法二是在方法一的基础上,不进行第二轮即从右至左的遍历,但此时只能解决递增分数的分配,那如何解决递减的分配呢?现在观察下递减分数 [ 5 , 4 , 3 , 2 , 1 ] [5,4,3,2,1] [5,4,3,2,1],首先先分配第一个孩子,数量分配1;现在分配第二个孩子至少为1,发现其分数小于第一个孩子,因此第一个孩子的分配糖数应该加1;同理,第三个孩子分配的时候,前两个孩子的糖数都应该各自加1,;进一步的第四个孩子分配时前三个孩子的糖数都应该各自加1、第五个分配时前四个孩子的糖数都应该各自加1,观察发现没有,总的增加的糖数是连续递减序列的个数。
  因此,针对递增的情况,采用从左至右变量的方法,一旦遇到递减则记录其长度,每增加一个长度,则分配的糖的数目直接加上递减序列的长度即可。但需要注意的是,递减是严格递减。,如果不是严格递减相等的时候,此时分配的糖数又可从1开始,但有个细节需要注意的时,例如 [ 1 , 6 , 10 , 8 , 7 , 3 , 2 ] [1,6,10,8,7,3,2] [1,6,10,8,7,3,2],其中10既属于递增,又属于递减,这时候为了保证10比两边都大,当递减序列等于10在递增分配的颗数时,下一步应该把10也纳入递减序列考虑了,故需判断上一个递增分配的最大糖数是否和递减序列长度相等,相等则递减序列长度需增加1。

3.代码实现

3.1 Python

# 方法一:
class Solution:
    def candy(self, ratings: List[int]) -> int:
        ans = [1 for _ in ratings]
        length = len(ratings)
        for i in range(1, length):
            if ratings[i] > ratings[i-1]:
                ans[i] = ans[i-1] + 1
        for i in range(length-2,-1, -1):
            if ratings[i] > ratings[i+1]:
                ans[i] = max(ans[i], ans[i+1]+1)
        return sum(ans)

    

在这里插入图片描述

# 方法二
class Solution:
    def candy(self, ratings: List[int]) -> int:
        # 题目已经提示孩子数至少为1,因此不用考虑长度的异常情况了
        ans = 1  # 总数目
        n = 0  # 递减序列长度
        pre = 1 # 前孩子糖数
        inc = 1 # 递增序列最大分数糖数
        for i in range(1, len(ratings)):
            if ratings[i] >=  ratings[i-1]:
                n = 0
                pre = 1 if ratings[i]==ratings[i-1] else pre+1  # 当前孩子的分配糖数
                ans += pre
                inc = pre
            else:
                n += 1
                if n == inc:  # 如果递减序列的长度已经等于递增的糖数了,此时也应该把递增的最大值加入递减序列
                    n += 1
                ans += n  # 把增加的糖数加上
                pre = 1  # 前糖数又变为1
        return ans

在这里插入图片描述

3.2 Java

//方法一:
class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int ans[] = new int[n];
        ans[0] = 1;
        for (int i=1;i<n;i++){
            if (ratings[i] > ratings[i-1]){
                ans[i] = ans[i-1]+1;
            }else{
                ans[i]=1;
            }
        }
        for (int i=n-2;i>-1;i--){
            if (ratings[i]>ratings[i+1]){
                ans[i] = ans[i]>ans[i+1]+1 ? ans[i] : ans[i+1]+1;
            }
        }
        return Arrays.stream(ans).sum();
    }
}

在这里插入图片描述

//方法二:
class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int res = 1;  //初始化结果
        int inc = 1;  //递增序列最后一个分配数
        int len = 0;  //递减序列长度
        int pre = 1;  //前分配数
        for (int i=1;i<n;i++){
            if (ratings[i] >= ratings[i-1]){
                len = 0;
                pre = ratings[i] == ratings[i-1] ? 1 : pre+1;
                res += pre;
                inc = pre;
            }else{
                len++;
                len = len==inc ? ++len : len;
                res += len;
                pre = 1;
            }
        }
        return res;
    }
}

在这里插入图片描述

  执行用时不必过于纠结,对比可以发现,对于python和java完全相同的编写,java的时间一般是优于python的;至于编写的代码的执行用时击败多少对手,执行用时和网络环境、当前提交代码人数等均有关系,可以尝试完全相同的代码多次执行用时也不是完全相同,只要确保自己代码的算法时间复杂度满足相应要求即可,也可以通过点击分布图查看其它coder的code

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raykingl

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值