算法刷题打卡027 | 贪心算法

贪心算是一种常识性的思路,没有固定规律套路可以总结,有时会和动态规划混淆,反正记住一点,就是能从子问题的局部最优推导出全局最优解。

LeetCode 455 分发饼干

题目链接:455. 分发饼干 - 力扣(Leetcode)

自己做题时想到用小尺寸的饼干优先满足小胃口的孩子,在代码实现时先遍历饼干,再遍历孩子,但写着写着思路有些混乱和不确定,一直想会不会有反例,干脆去看题解梳理一下。实际思路和遍历顺序没有问题,就是不自信:

class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        g.sort()
        s.sort()
        # 遍历饼干
        j = 0
        res = 0
        for i in range(len(s)):
            # 胃口最小的孩子优先给饼干
            if j < len(g) and g[j] <= s[i]:
                res += 1
                j += 1
        return res
            

当时思路混乱主要是因为for循环内部想用while遍历g,思维就陷入了怪圈。

LeetCode 376 摆动序列

题目链接:376. 摆动序列 - 力扣(Leetcode)

这题乍一看没什么思路,只能看讲解了,然后发现我一开始的找局部最大最小值的思路是对的,但数数数错了,以为方案不可行,而代码实现还得考虑边界条件,以及平坡的问题。看力扣评论区同学的思路很简洁,这里借鉴一下:

class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        # 借鉴评论区PlanB同学的思路,平坡的相等元素直接跳过,通过flag记录上一次是上坡还是下坡
        Sum, flag = 1, 0   # 结果初始化为1,考虑了两端
        for i in range(1, len(nums)):
            if nums[i] > nums[i-1] and (flag == 0 or flag == -1):
                Sum += 1
                flag = 1  # 当前差值为正数
            elif nums[i] < nums[i-1] and (flag == 0 or flag == 1):
                Sum += 1
                flag = -1
        return Sum

代码随想录中还介绍了动态规划和线段树优化的思路,之后有时间可以再回顾。

LeetCode 53 最大子序和

题目链接:

虽然是简单题,但看到一刷时我写的是动态规划的解法,感觉事情不简单:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        res = nums[0]
        # dp数组表示以位置i结尾的子数组的最大和
        dp = [0 for _ in range(n)]
        dp[0] = nums[0] # 初始化
        for i in range(1, n):
            # 两种情况:在dp[i-1]的基础上考虑当前的元素,加上nums[i];
            # 第二种情况是dp[i-1]与nums[i]和为负数,则子数组从当前位置重新开始
            dp[i] = max(dp[i-1] + nums[i], nums[i])
        # 选取dp数组中的最大值
        for i in range(n):
            res = max(res, dp[i])
        return res

印象中这是最初让我比较困扰的动态规划类型题,稀里糊涂地过了(痛苦面具),但感觉讲解中的贪心思路和上面的代码实现很相似,“局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。” 并且数组中的元素包含负数,贪心比较的时候不能和0比,而是和数据范围之外的负数比:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        # 贪心
        res = float('-inf')
        s = 0
        for i in range(n):
            s += nums[i]
            # 及时收集当前最大子数组和的结果,相当于动态调整子数组右边界
            if s > res:
                res = s
            # 贪心
            if s <= 0:
                s = 0
        return res

你可能感兴趣的:(刷题,算法,贪心算法,leetcode)