代码随想录学习Day 27

贪心算法理论基础

贪心的本质:通过每一阶段的局部最优推出全局最优。

思路:找局部最优,看能不能推出全局最优,并尝试举反例。

步骤:

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优

455.分发饼干

题目链接

讲解链接

首先想到的解法是先将s数组和g数组按照从小到大的顺序排序,然后用两个for循环来遍历两个数组,外层遍历g数组,内层遍历s数组,每次遇到满足g[i] < s[i]的情况时就将result+1,然后将s[i]置零代表这篇饼干已被使用过,并跳出当前层循环;若不满足则直接continue,查找下一片饼干。总体思路就是优先满足胃口小的孩子。

python 复制代码
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        s.sort()  # 排序,从小到大
        g.sort()  # 使小胃口的孩子和小饼干排列在前
        result = 0  # 结果初始为0
        for i in range(len(g)):  # 遍历孩子数组
            for j in range(len(s)):  # 遍历饼干数组
                if g[i] > s[j]:  # 意味着饼干不能满足孩子胃口,直接跳过,寻找下一块饼干
                    continue
                else:
                    s[j] = 0  # 满足条件则将当前饼干置零,防止后续再被使用
                    result += 1
                    break
        return result

优化版本,不需要使用两个for循环,降低时间复杂度:

python 复制代码
class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        s.sort()
        g.sort()
        index = 0  # 用一个index来遍历胃口
        for i in range(len(s)):  # for循环遍历饼干
            if index < len(g) and g[index] <= s[i]:  # 仅当满足条件时,index才会+1
                index += 1
        return index  # 返回index,也就是消耗的饼干数

这里必须外层遍历饼干,内层遍历胃口才可以,因为外层循环的i是固定移动的,内层的index只有在满足条件时才会移动,如果交换顺序就会导致一直在用最小的饼干来对比所有孩子的胃口,从而无法得出结果。

376.摆动序列

题目链接

讲解链接

思路:局部最优------删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值整体最优------整个序列有最多的局部峰值,从而达到最长摆动序列

实际上不需要进行删除操作,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)。如果前一对差值prediff与当前对差值curdiff的乘积小于0,那么就说明当前是一处摆动。代码如下:

python 复制代码
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        if len(nums) <= 1:  # 如果数组长度小于等于1,那么则直接返回数组的长度
            return len(nums)
        prediff, curdiff, result = 0, 0, 1  # 初始化前一对差值,当前差值和结果,因为输出的结果是序列的长度,所以结果的初值要设置为1(单纯计算正负差值的对数的结果与序列长度相差1)
        for i in range(1, len(nums)):  # 遍历数组,从1开始
            curdiff = nums[i] - nums[i - 1]  # 计算当前差值
            if curdiff * prediff <= 0 and curdiff != 0:  # 若当前差与前一对差乘起来的结果是负数或0,且当前差值不为0,那么说明出现了摆动
                result += 1  # 结果+1
                prediff = curdiff  # 只有出现摆动时才令前一对差等于当前差
        return result

53.最大子数组和

题目链接

讲解链接

暴力解法,容易想到但会超时。

python 复制代码
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        result = float('-inf')  # 结果初始为无穷小
        for i in range(len(nums)):  # i对应遍历的起始位置
            sum = 0  # 每次改变起始位置时都将sum置零
            for j in range(i, len(nums)):  # 每次从j从i开始遍历寻找最大值
                sum += nums[j]
                if sum > result:  # 如果sum大于之前的result,就进行赋值
                    result = sum
        return result

贪心思路:

**局部最优------当前"连续和"为负数的时候立刻放弃,从下一个元素重新计算"连续和",因为负数加上下一个元素 "连续和"只会越来越小。**全局最优------选取最大"连续和"

遍历 nums,从头开始用sum累积,如果sum一旦加上nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积sum了,因为已经变为负数的sum,只会拖累总和。

这相当于是暴力解法中的不断调整最大子序和区间的起始位置

python 复制代码
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        result = float('-inf')  # result初始为无穷小
        sum = 0  # 连续和初始为0
        for i in range(len(nums)):  # 遍历数组
            sum += nums[i]  # 将第i个元素加到连续和上
            if sum > result:  # 如果当前连续和大于result,则更新result的值
                result = sum
            if sum < 0:  # 如果连续和小于0,则直接舍弃
                sum = 0  # 将连续和置零
                continue  # 从下一个i开始重新计算,类似于暴力法的移动起始位置
        return result
相关推荐
行然梦实9 分钟前
学习日记_20241110_聚类方法(K-Means)
学习·kmeans·聚类
马船长14 分钟前
制作图片木马
学习
秀儿还能再秀26 分钟前
机器学习——简单线性回归、逻辑回归
笔记·python·学习·机器学习
WCF向光而行30 分钟前
Getting accurate time estimates from your tea(从您的团队获得准确的时间估计)
笔记·学习
wang09071 小时前
工作和学习遇到的技术问题
学习
Li_0304062 小时前
Java第十四天(实训学习整理资料(十三)Java网络编程)
java·网络·笔记·学习·计算机网络
心怀梦想的咸鱼2 小时前
ue5 蓝图学习(一)结构体的使用
学习·ue5
kali-Myon2 小时前
ctfshow-web入门-SSTI(web361-web368)上
前端·python·学习·安全·web安全·web
龙中舞王3 小时前
Unity学习笔记(4):人物和基本组件
笔记·学习·unity
Hncj20223 小时前
MySQL学习/复习2库的操作
学习