Day 31 貪心: 455. 分發(fā)餅干, 376. 擺動序列, 53. 最大子數(shù)組和

貪心算法 簡介

  • 局部最優(yōu) \Longrightarrow 整體最優(yōu)

455. 分發(fā)餅干

  • 思路
    • example
    • 你的目標是盡可能滿足越多數(shù)量的孩子,并輸出這個最大數(shù)值。
    • 可以全部餅干都分給一個人涣达。
    • 每個孩子最多只能給一塊餅干截亦,餅干只能整個給辨图。
    • g[i]: 第i個人胃口值
    • s[j]: 第j個餅干尺寸
    • g[i] <= s[j]: 第i個人可以吃第j個餅干蒂破。
    • 貪心:兩個思路:(大餅干分小胃口可能造成“浪費”:小餅干可能沒用上)
      • 胃口小先分小餅干稀颁,或者胃口大后分大餅干 (小孩視角)
      • 小餅干給小胃口芬失,或者大餅干給大胃口 (餅干視角)
      • 需要對g,s進行排序
    • 選定視角 (雙指針,單層循環(huán))
      • 小孩胃口
      • 餅干
      • 注意循環(huán)順序(逆序峻村?)的選取 (餅干視角麸折,順序更好;小孩視角粘昨,逆序更好)


  • 復(fù)雜度. 時間:O(m+n), 空間: O(1)
# 每一步喂一個小孩
# 這里比較麻煩垢啼,需要嵌套j-循環(huán)。
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort()
        s.sort()
        res = 0
        j = 0 # j: 餅干index
        for i in range(len(g)): # i: 小孩胃口index
            while j < len(s) and g[i] > s[j]: # 找到符合胃口的最小餅干
                j += 1
            # jth餅干 喂 ith小孩
            if j < len(s):
                res += 1
                j += 1
        return res 
  • 稍微不同的寫法
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort()
        s.sort()
        res = 0
        j = 0 # j: 餅干index
        i = 0 # i: 小孩胃口index
        while i < len(g) and j < len(s):
            while j < len(s) and g[i] > s[j]: # 找到符合胃口的最小餅干
                j += 1
            # jth餅干 喂 ith小孩
            if j < len(s):
                res += 1
                i += 1
                j += 1
        return res 
  • 餅干視角 (餅干順序遍歷张肾,餅干小了可以直接跳過)
    • 小餅干給胃口小
    • 更簡潔
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort()
        s.sort()
        res = 0
        j = 0 # j: 餅干index
        i = 0 # i: 小孩胃口index
        for j in range(len(s)):
            if i < len(g) and s[j] >= g[i]: # jth餅干喂給ith小孩
                res += 1
                i += 1 # 下一個小孩
            # 否則jth餅干沒用芭析,直接下一個餅干
        return res 
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        # Greedy:大餅干給大胃口
        s.sort() # 餅干大小排序 
        g.sort() # 胃口大小排序
        i, j = len(g)-1, len(s)-1
        res = 0
        while j >= 0 and i >= 0:
            while i >= 0 and g[i] > s[j]: # 注意越界檢查
                i -= 1
            # now g[i] <= s[j], 餅干j可以給小孩i 
            if i >= 0: # 確保能找到滿足要求的小孩i
                res += 1
                j -= 1
                i -= 1
        return res 
  • 大給大,小給小
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        if len(g) == 0 or len(s) == 0:
            return 0 
        g.sort()
        s.sort()
        res = 0
        j = len(s)-1
        i = len(g)-1
        while j >=0 and i>= 0:
            if s[j] >= g[i]:
                res += 1
                j -= 1
                i -= 1
            else:
                i -= 1 
        return res 
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        m, n = len(g), len(s)  
        if m == 0 or n == 0:
            return 0 
        cnt = 0 
        g.sort()  
        s.sort()  
        j, i = n-1, m-1  
        while j >= 0 and i >= 0:
            if s[j] >= g[i]:
                cnt += 1
                j -= 1
                i -= 1
            else:
                i -= 1
        return cnt   

376. 擺動序列

  • 思路
    • example
    • 返回 nums 中作為 擺動序列 的 最長子序列的長度 吞瞪。
      • 子序列 可以通過從原始序列中刪除一些(也可以不刪除)元素來獲得馁启,剩下的元素保持其原始順序。
    • 貪心法
      • 差分數(shù)列:e.g., [+,+,-,+,-,-,+], ans = 5
      • 注意差分==0的情況:[0,+,+,-], ans = 2
      • 維護兩個符號指針 pre, cur
        • pre<=0, cur>0: res += 1
        • pre>=0, cur<0: res += 1
        • 比如nums = [1,2], 可以假設(shè)數(shù)組為[1,1,2],這樣pre初始化為0芍秆。
  • 復(fù)雜度. 時間:O(n), 空間: O(1)
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        pre_diff = 0
        res = 1
        for i in range(1, n):
            cur_diff = nums[i] - nums[i-1]
            if cur_diff > 0:
                cur_diff = 1
            elif cur_diff < 0:
                cur_diff = -1
            # else: cur_diff = 0
            if (pre_diff <= 0 and cur_diff > 0) or (pre_diff >= 0 and cur_diff < 0):
                res += 1
                pre_diff = cur_diff # 不能放在外面, 比如 +,0,+ 情況
        return res 
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return 1 
        res = 0
        pre = 0
        for i in range(1, n):
            diff = nums[i] - nums[i-1]
            if diff == 0:
                continue
            elif diff > 0:
                cur = 1
                if cur != pre:
                    res += 1
                    pre = cur 
            else:
                cur = -1
                if cur != pre:
                    res += 1
                    pre = cur  
        return res + 1
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        if n <= 1:
            return n 
        res = 1
        pre = 0 # pre sign: 
        for i in range(1, n):
            cur = nums[i] - nums[i-1] 
            if cur > 0:
                if pre <= 0:
                    res += 1
                    pre = cur 
            elif cur < 0:
                if pre >= 0:
                    res += 1
                    pre = cur 
            # else: pre does not change 
        return res 
  • DP 方法
    • dp[i][0]: ith結(jié)尾為高峰的擺動子列最長長度
    • dp[i][1]: ith結(jié)尾為低谷的擺動子列最長長度
    • 時間: O(n^2), 可以做到O(n \log(n)如果優(yōu)化內(nèi)部搜索惯疙。
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        dp = [[1] * 2 for _ in range(len(nums))]
        res = 1
        for i in range(len(nums)):
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i][0] = max(dp[j][0], dp[j][1]+1)
                    res = max(res, dp[i][0])
                if nums[i] < nums[j]:
                    dp[i][1] = max(dp[j][1], dp[j][0]+1)
                    res = max(res, dp[i][1])
        return res 
        # or return max(dp[-1][0], dp[-1][1])

53. 最大子數(shù)組和

  • 思路
    • example
    • 請你找出一個具有最大和的連續(xù)子數(shù)組(子數(shù)組最少包含一個元素), 返回其最大和。
    • 滑動窗口, DP, (也可以用貪心來解釋)
    • 考慮以ith結(jié)尾的連續(xù)子數(shù)組的最大和dp[i]
      • 如果dp[i-1] < 0, 則dp[i] = nums[i] (只考慮當前一個數(shù))
      • 如果dp[i-1]>=0, 則dp[i] = dp[i-1] + nums[i]
      • 或者dp[i] = max(nums[i], dp[i-1] + nums[i])
      • 可空間優(yōu)化
      • 注意不能根據(jù)nums[i-1]的正負來判斷妖啥。
  • 復(fù)雜度. 時間:O(n), 空間: O(1)
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0 for _ in range(n)]
        dp[0] = nums[0]
        res = dp[0]
        for i in range(1, n):
            dp[i] = max(dp[i-1] + nums[i], nums[i])
            res = max(res, dp[i])
        return res 
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        cur_sum, res = 0, -float('inf')
        for i in range(len(nums)):
            cur_sum = max(cur_sum + nums[i], nums[i])
            res = max(res, cur_sum)
        return res 
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0 for _ in range(n)]
        dp[0] = nums[0]
        res = dp[0]
        for i in range(1, n):
            if dp[i-1] < 0:
                dp[i] = nums[i]
            else:
                dp[i] = dp[i-1] + nums[i]
            res = max(res, dp[i])
        return res 
  • 分治法
    • 分三種情況:左半部結(jié)果霉颠,右半部結(jié)果,“中間結(jié)果”:橫跨中心的連續(xù)子數(shù)組的結(jié)果
TBA
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荆虱,一起剝皮案震驚了整個濱河市蒿偎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怀读,老刑警劉巖诉位,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異菜枷,居然都是意外死亡苍糠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門啤誊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椿息,“玉大人歹袁,你說我怎么就攤上這事坷衍∏抻牛” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵枫耳,是天一觀的道長乏矾。 經(jīng)常有香客問我,道長迁杨,這世上最難降的妖魔是什么钻心? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮铅协,結(jié)果婚禮上捷沸,老公的妹妹穿的比我還像新娘。我一直安慰自己狐史,他們只是感情好痒给,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著骏全,像睡著了一般苍柏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姜贡,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天试吁,我揣著相機與錄音,去河邊找鬼楼咳。 笑死熄捍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的母怜。 我是一名探鬼主播余耽,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼糙申!你這毒婦竟也來了宾添?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柜裸,失蹤者是張志新(化名)和其女友劉穎缕陕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疙挺,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡扛邑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铐然。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔬崩。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恶座,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沥阳,到底是詐尸還是另有隱情跨琳,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布桐罕,位于F島的核電站脉让,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏功炮。R本人自食惡果不足惜溅潜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望薪伏。 院中可真熱鬧滚澜,春花似錦、人聲如沸嫁怀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眶掌。三九已至挡育,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朴爬,已是汗流浹背即寒。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留召噩,地道東北人母赵。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像具滴,于是被迫代替她去往敵國和親凹嘲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容