1. 程式人生 > 其它 >【Leetcode每日筆記】135.分發糖果(Python)

【Leetcode每日筆記】135.分發糖果(Python)

技術標籤:LeetCode一週一結leetcode貪心演算法演算法全域性最優常數空間

文章目錄

題目描述

老師想給孩子們分發糖果,有 N 個孩子站成了一條直線,老師會根據每個孩子的表現,預先給他們評分。

你需要按照以下要求,幫助老師給這些孩子分發糖果:

每個孩子至少分配到 1 個糖果。
相鄰的孩子中,評分高的孩子必須獲得更多的糖果。

那麼這樣下來,老師至少需要準備多少顆糖果呢?

示例 1:

輸入: [1,0,2] 輸出: 5 解釋: 你可以分別給這三個孩子分發 2、1、2 顆糖果。

示例 2:

輸入: [1,2,2] 輸出: 4 解釋: 你可以分別給這三個孩子分發 1、2、1 顆糖果。
第三個孩子只得到 1 顆糖果,這已滿足上述兩個條件。

解題思路

思路一——貪心演算法

這道題目一定是要確定一邊之後,再確定另一邊,例如比較每一個孩子的左邊,然後再比較右邊,如果兩邊一起考慮一定會顧此失彼
全域性最優:相鄰的孩子中,評分高的右孩子獲得比左邊孩子更多的糖果。
區域性最優可以推出全域性最優。
先確定右邊評分大於左邊的情況(也就是從前向後遍歷)
貪心區域性最優:只要右邊評分比左邊大,右邊的孩子就多一個糖果candies[i]=candies[i-1]+1
再確定左邊評分大於右邊的情況(也就是從後向前遍歷)

繼續貪心區域性最優:只要左邊的評分比右邊的大,左邊的孩子就多一個糖果,即candies[i+1]+1
兩者結合達到全域性最優:再從後往前遍歷過程中,求得全域性最優max(candies[i],candies[i+1]+1)

思路二——常數空間一次遍歷

對於一個無序的數列,它一定是由若干遞增數列和遞減數列組成,如[1,2,5,6,4,3,2,5,3],可以看出這個陣列的單調性為先增後減,再增再減。所以可以將題目中的問題轉化為對若干單調數列求和的問題,那我們只需要知道每一段單調數列的長度即可。
結合題目中的至少,保證每個孩子獲得的糖果要儘可能的少。那麼數列的最小的數一定是以1開始,並且公差為1遞增或者遞減。以ratings:[1,2,8,6,5,3,1]為例,前三項[1,2,5]遞增,那麼糖果分配是candies1:[1,2,3],後面[5,4,3,2,1]為遞減,那麼糖果分配為candies2:[5,4,3,2,1],可以發現兩次糖果分配中‘8’分配了不同的糖果數,那麼此時取大的兩者中大的數即可保證都滿足。

考慮相等的情況。ratings: [1,2,2] ,candies:[1,2,1]
那麼對於遞增和相等的情況,我們單獨加入結果,出現遞減數列,我們先獲取遞減區間的長度,根據等差數列求和公式求出區間的和,即這一區間的糖果數,再對等差數列首項取最大。
在這裡插入圖片描述

程式碼

思路一

class Solution:
    def candy(self, ratings: List[int]) -> int:
        candies = [1]
        for i in range(1,len(ratings)):
            if ratings[i] > ratings[i-1]:
                candies.append(candies[i-1]+1)
            else:
                candies.append(1)
        for i in range(len(ratings)-2,-1,-1):
            if ratings[i] > ratings[i+1]:
                candies[i] = max(candies[i],candies[i+1]+1)
        return sum(candies)            

思路二

class Solution:
    def candy(self, ratings: List[int]) -> int:
        res = 1
        cur = 1
        des_num = 0
        for i in range(1,len(ratings)):
            if ratings[i] >= ratings[i-1]:
                if des_num > 0:
                    res += (des_num*(des_num+1))//2
                    if cur <= des_num:
                        res += des_num+1-cur
                    cur = 1
                    des_num = 0
                if ratings[i] == ratings[i-1]:
                    cur = 1
                else:
                    cur += 1
                res += cur
            else:
                des_num += 1
            
        if des_num > 0:
            res += (des_num*(des_num+1))//2
            if cur <= des_num:
                res += des_num+1-cur
        return res