代码随想录学习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
相关推荐
科技林总11 小时前
【系统分析师】11.5 软件需求文档化
学习
python零基础入门小白11 小时前
多智能体强化学习:从基础到实战,掌握协作与竞争的艺术!
人工智能·学习·chatgpt·大模型·产品经理·ai大模型·大模型学习
arvin_xiaoting12 小时前
从 0 到 1:搭建自学习 AI Agent 系统的完整工程指南
人工智能·学习·系统设计·ai agent·lancedb·自学习·openclaw
飞Link12 小时前
深度解析 TS2Vec:时序表示学习中的层次化建模(Hierarchical Contrastive Learning)
开发语言·python·学习·数据挖掘
格鸰爱童话12 小时前
向AI学习项目技能(二)
java·人工智能·python·学习
知识分享小能手13 小时前
PostgreSQL 入门学习教程,从入门到精通,PostgreSQL 16 服务器配置与数据库监控终极指南 —语法、案例与实战(18)
数据库·学习·postgresql
困死,根本不会13 小时前
蓝桥杯python备赛笔记之(八)动态规划(DP)
笔记·python·学习·算法·蓝桥杯·动态规划
懷淰メ13 小时前
python3GUI--socket+PyQt5开发局域网微信(含功能、详细介绍、分享)
python·学习·gui·大学生·pyqt5·微信界面
ByNotD0g13 小时前
Doris 学习笔记
android·笔记·学习
困死,根本不会13 小时前
Qt Designer 基础操作学习笔记
开发语言·笔记·qt·学习·microsoft