【Day31】代码随想录之贪心算法part1——理论基础、分发饼干、摆动序列、最大子序和

本文介绍了贪心算法的基本概念,包括其本质、适用场景和解题步骤,以及通过实例如分发饼干、摆动序列和最大子序和问题来详细阐述贪心策略的应用。同时,对比了贪心与动态规划的区别,并提供了LeetCode题目中的代码示例。
摘要由CSDN通过智能技术生成

昨天把N皇后、解数独问题跳过去了,等二刷再去做,今天开始贪心算法部分,开冲!!!

卡哥忠告:
(1)贪心算法其实就是没有什么规律可言,所以大家了解贪心算法 就了解它没有规律的本质就够了;
(2)不用花心思去研究其规律, 没有思路就立刻看题解;
(3)基本贪心的题目有两个极端,要不就是特简单,要不就是死活想不出来;
(4)学完贪心之后再去看动态规划,就会了解贪心和动规的区别。

贪心的理论基础

1.1 题目大纲:

在这里插入图片描述

1.2 什么是贪心?

贪心的本质就是选择每一阶层的局部最优,从而达到全局最优。
贪心的例子:有一堆钞票,若可以拿走十张,如何达到最大金额?可以每次都拿最大的,最终结果就是拿走最大数额的钱。
动规的例子:如果有一堆盒子,如果有个背包体积为n,尽可能地把背包装满,此时贪心就不行了,需要动态规划。

1.3 什么时候用贪心?

1、我们在做贪心题目的时候,有没有套路一看这个就是贪心? 贪心算法并没有固定的套路,说白了就是常识性推到 + 举反例。
2、如何看出局部最优是否能推出整体最优呢?有没有什么固定的策略或者套路呢(就像回溯算法一样)? 也没有,靠自己手动模拟下,如果模拟可行,就可以试下贪心策略,如果不可行,则采用动态规划。
3、如何验证可不可以用贪心算法呢? 最好用的就是举反例,如果想不到反例,那就可以试一下贪心

1.4 贪心一般的解题步骤

贪心算法一般分为如下四步(很鸡肋):

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

需要重点思考的:每阶段的局部最优是什么?局部最优是否可以推导出全局最优?

题目一:455.分发饼干

Leetcode题目:【455.分发饼干】
参考:【代码随想录之分发饼干】

在这里插入图片描述

思路: 此处代码的贪心思路非常简单,就是首先需要两个数组排个序,按照大饼干去喂胃口比较大的孩子的策略,每步都这样做就可以达到全局最优。

在这里插入图片描述

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int result = 0;
        int index = s.size() - 1;
        for(int i = g.size() - 1; i>=0; i--){
            if(index >= 0 && s[index] >= g[i]){
                result++;
                index--;
            }
        }
        return result;
    }
};

此处还有个C++的语法问题,如果对数组进行逆向排序(从大到小排序),此处需要注意cmp修饰的一定是静态的,因为如果不是静态的话,编译器在编译的时候会自动带上this-> cmp,而sort是库函数提供的,不能是认为专属的某一类修饰的东西,所以需要定义成静态的。

// 只需要定义个这样的函数
    static bool cmp(int x, int y){
        return x > y;
    }

sort(s.begin(), s.end(), cmp);

题目二:376.摆动序列

Leetcode题目:【376.摆动序列】
参考:【代码随想录之摆动序列】

在这里插入图片描述
这道题目做起来还是比较难的,需要思考的点:
(1)序列特殊个数为0、1、2情况下,直接返回序列的长度值即可;
(2)如何实现正负数摆动序列的操作,只需要定义两个变量一个prediff,一个curdiff;当prediff * curdiff < 0,说明两者异号,满足情况
(3)平坡情况:

  • 首尾元素如何计算?不能用result = 2,首位直接算进去,因为如果序列是[1,1,1,1,1],返回的应该是1,而非2;所以result = 1,然后最后一位可以不进行判断;
  • 上下坡出现平坡:考虑pre = 0,curdiff>0或者curdiff<0,这个也要算进去1次;
  • 单调坡出现平坡:也满足pre = 0,cur > 0 或者curdiff<0,但是这个就不能算进去;

针对情况上下坡和单调坡出现的相矛盾的问题,只需要让prediff不是完全随着curdiff走,而是prediff只记录有坡度变化的curdiff的值,也就是跟着result走。

最复杂的摆动序列的情况如下所示:

在这里插入图片描述


class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if(nums.size() == 1) return 1;
        if(nums.size() == 2 && nums[0] == nums[1]) return 1;
        if(nums.size() == 2 && nums[0] != nums[1]) return 2;
        int result = 1;
        int prediff = 0, curdiff = 0;
        for(int i = 0; i< nums.size() - 1; i++){
            curdiff = nums[i + 1] - nums[i];
            if((prediff>=0 && curdiff <0) || (prediff<=0 && curdiff>0)){
                result++;
                prediff = curdiff;
            }
        }
        return result;

    }
};

题目三:53.最大子序和

Leetcode题目:【53.最大子序和】
参考:【代码随想录之最大子序和】

在这里插入图片描述
连续和 + 一个负数只能让连续和变小,因此可以利用这一点,可以选取起始位置。终止位置,遇到了最大值做一个统计,然后既可以记录终止位置。

在这里插入图片描述

class Solution {
public:
    int result = INT_MIN;
    int temp = 0;
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==1) return nums[0];
        for(int i = 0; i<nums.size(); i++){
            temp += nums[i];
            if(temp > result) result = temp;
            if(temp < 0){
                temp = 0;
            }
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值