贪心算法(局部最优实现全局最优)第一篇

目录

[1. 什么是贪心算法](#1. 什么是贪心算法)

[2. 贪心算法的解题步骤](#2. 贪心算法的解题步骤)

[3. 具体例题及代码](#3. 具体例题及代码)

[3.1 LeetCode860. 柠檬水找零](#3.1 LeetCode860. 柠檬水找零)

[3.2 LeetCode2208. 将数组和减半的最少操作次数](#3.2 LeetCode2208. 将数组和减半的最少操作次数)

[3.3 LeetCode179. 最大数](#3.3 LeetCode179. 最大数)


从这篇文章开始,我们开始讲解贪心算法。

1. 什么是贪心算法

贪心算法是算法设计中的经典思想,核心逻辑用一句话就能概括 ------每一步都做出当前情况下的最优选择,不回头、不纠结,最终期望得到全局最优解。它不像动态规划那样依赖中间状态存储,也不用回溯尝试所有可能,凭借 "直来直往" 的思路,成为解决特定问题的高效方案。

2. 贪心算法的解题步骤

  1. 问题拆解:将复杂问题拆分成多个连续的局部决策步骤。
  2. 确定贪心策略:明确每一步的 "最优标准"(比如 "选最小""选最大""选最早结束")。
  3. 验证可行性:确认该策略能满足 "局部最优推全局最优",避免无效贪心
  4. 代码实现:通常先排序(按策略对应的规则),再遍历执行贪心选择。

之所以给第三步加粗,是因为这一步在我看来是最重要的。因为有些题目看起来好像可以使用贪心,但是实际上是不可以的,很多时候局部最优达不到全局最优解。

同时在我看来它也没有具体的模版,因为它要根据每一题来设计不同的贪心思路。我觉得贪心最重要的就是经验。

3. 具体例题及代码

3.1 LeetCode860. 柠檬水找零

我们看下面这张图片,要求是模拟实现找零,那么我们的策略就是每一次都尽量给大的零钱,因为这样我们可以确保只会出现零钱不够的情况,不会出现有钱但是无法使用的情况。

所以代码设计也很简单,就是找零能用大的就用大的,就这样设计就好了。在我们一开始对于贪心算法的学习过程中我觉得最重要的就是我们可以想到使用贪心算法。

其实这道题的代码也很好写,就是几个条件判断就好了。

cpp 复制代码
class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int a=0;//5
        int b=0;//10
        int c=0;//20
        int sz=bills.size();
        for(int i=0;i<sz;++i)
        {
            int num=bills[i];
            if(num==20)
            {
                if(b&&a)
                {
                    b--;
                    a--;
                    c++;
                }
                else if(a>3||a==3)
                {
                    a-=3;
                    c++;
                }
                else
                    return false;
            }
            if(num==10)
            {
                if(a)
                {
                    a--;
                    b++;
                }
                else
                    return false;
            }
            if(num==5)
                a++;
        }
        return true;
    }
};

3.2 LeetCode2208. 将数组和减半的最少操作次数

我们看下面这道题,题目要求我们最小次数的对数组里面的数除以2,使数组和小于等于原先数组的一半。其实从题目上我们很好想到,就是每次找数组里面最大的数,然后给它减去一半。

我们看下面这个代码,其实我们只要知道priority_queue就可以很快的做出来这道题,priority_queue是默认大堆的,所以我们在这里就不用更改。同时它每插入一个数都会对其进行排序,所以我们只要不断的取出堆顶的元素就好了。

cpp 复制代码
class Solution {
public:
    int halveArray(vector<int>& nums) {
        priority_queue<double> p;
        double a1=0;
        double a2=0;
        for(auto& a:nums)
        {
            a1+=a;
            a2+=a;
            p.push(a);
        }
        a1/=2;
        int mem=0;
        while(a1<a2)
        {
            double tmp=p.top()/2;
            p.pop();
            a2-=tmp;
            p.push(tmp);
            mem++;
        }
        return mem;
    }
};

3.3 LeetCode179. 最大数

题目的意思就是给我们一个数组,然后我们要用数组里面的数来组成一个最大的数。所以我们根据组合后数字的大小来排序。

我们看代码,因为知道是通过组合后数字的大小来排序,所以我们在这里就直接通过一个lambda 表达式,给sort重写排序规则,就可以做出来这道题了。

cpp 复制代码
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> str;
        for(auto& s:nums)
            str.push_back(to_string(s));
        sort(str.begin(),str.end(),[](const string& s1,const string&s2){
            return s1+s2>s2+s1;
        });
        string tmp;
        for(auto& s:str)
            tmp+=s;
        if(tmp[0]=='0')
            return "0";
        else
            return tmp;
    }
};
相关推荐
GreenTea2 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Bode_20022 小时前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
土司大王3 小时前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹3 小时前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
土司大王3 小时前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
罗西的思考5 小时前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习
小哈里6 小时前
【知识】从学科到实践:自然・工程・社科・人文|算法・研发・产品・品牌设计
程序人生·算法·产品·设计·工程
小π军6 小时前
最大重叠区间数量
数据结构·算法
镜像视界(浙江)科技有限公司7 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算
a187927218317 小时前
【算法】双指针与滑动窗口(二):滑动窗口——吃进、判定、吐出
算法·leetcode·双指针·滑动窗口·原理·模板·算法讲解