【Hello Algorithm】贪心算法

本篇博客介绍: 简单介绍下贪心算法

贪心算法

    • 介绍贪心算法
    • 最小字典序的字符串拼接
    • 最多会议数
    • 切棍子的最小成本
    • IPO
    • 灯塔问题

介绍贪心算法

贪心算法是一种极具有自然智慧的算法

它会使用以一种局部最功利的标准来做出一个当前看来最好的选择

如果说我们根据局部最优解算出了全局最优解 那么这就是一个有效的贪心

反之我们就可以说 这是一个无效的贪心

也就是说 我们用贪心算法做题是可能出错的!

贪心算法的难点在于 我们如何使用局部最功利的标准去得到全局最优解

所以说贪心算法并没有一套很固定的模板 对于贪心算法的学习我们只能是增加阅历和经验为主

下面是贪心算法的反例

现在A要从起点走到终点 再从终点走到起点 从起点到终点的过程中只能够向下或者向左 从终点到起点的过程中智能向上或者向右

在这里插入图片描述
如果我们根据贪心算法来解决 我们的思路是

  • 去的时候尽量拿到更多的节点
  • 回来的时候尽量拿到更多的节点

我们的路线应该是这样子的

在这里插入图片描述

我们可以发现我们少拿了一个节点

但是最佳的路线其实应该是这样子

在这里插入图片描述

我们全部的节点都拿到了

上面的例子只是为了证明 贪心算法也会出错

最小字典序的字符串拼接

题目如下:

给定我们一个由字符串拼接而成的数组strs 我们必须要把所有的字符串拼接出来 要求我们返回一个字典序最小的拼接结果

首先我们能够确定的是 我们最后拼接出来的字符串长度肯定是一样的

这里同学们一般的贪心策略可能是我们将字符串按照字典序排个序 然后直接拼接起来即可

虽然大部分情况下这种策略是对的 但是也有反例

比如说两个字符串 “b” “ba”

我们明显可以看出 拼接出的最小字符串应该是bab

可以如果按照我们的算法 我们得到的就是字符串bba 明显不对

正确的贪心算法如下

我们按照以下结果排序 如果a拼接上b 小于 b拼接上a 则a在前 反之b在前

使用我们正确的贪心算法就能够得到正确的结果 "bab"了

关于上面贪心的证明过程有点复杂 而且就算知道了如何证明也没有什么意义 其他的题目并不通用 这也就是为什么说学习贪心算法只是为了增加阅历

如果对于这个证明过程有兴趣的同学可以去b站查看左神的算法课学习

这道题我们可以在牛客网上做

最小字典序

代码表示如下

#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>bool Less(const string& s1 , const string& s2){return s1 + s2 < s2 + s1;}int main() 
{int count = 0;cin >> count;vector<string> strs;strs.resize(count);int i = 0;string str;while (count--){cin >> str;strs[i] = str;i++;}sort(strs.begin() , strs.end() , Less);string ans;for (int j = 0; j < strs.size() ; j ++){ans += strs[j];}cout << ans << endl;
}

还有就是 一般来说面试的时候不会考查贪心算法

如果考查了 那么我们可以直接跟面试官说 我不确定我的思路对不对 但是我可以使用对数器 一个个来验证我的思路

最多会议数

给你一个数组 events,其中 events[i] = [startDayi, endDayi] ,表示会议 i 开始于 startDayi ,结束于 endDayi 。

你可以在满足 startDayi <= d <= endDayi 中的任意一天 d 参加会议 i 。注意,一天只能参加一个会议。

请你返回你可以参加的 最大 会议数目。

这道题我们贪心的想法可能会有很多 比如说:

  • 我们每次排序之后选出时间最早的会议 之后继续排序
  • 我们每次选择间隔时间短的会议
  • 我们每次都选择结束时间最早的

显然 我们能够提出很多种贪心的方法 但是我们没有办法去一一证明 最快的方式就是直接写出一个暴力方式 然后将上面的几种方案全部写成代码 使用对数器一一对应

对数器能过 那就大概率是对的

我们这里直接给出结论 我们要选择每次开始时间最早的会议

因为我们要尽可能多的参加会议 所以说我们每天的时间最好都是能够用起来的

所以说 我尽量使用date日期来遍历

当然 题目中的隐藏条件就是可以使用的日期等于会议的最后一天 所以说我们也可以利用上这个隐藏条件

我们的整体思路如下

  • 首先将所有的会议 按照日期的开始进行排序
  • 我们创造一个小根堆 用来存放目前可以被使用的会议
  • 如果说当前的日期大于等于会议的开始日期 我们就将所有的会议开始日期进入堆中
  • 如果堆中存在可以开的会议我们就开会 如果不存在我们就data++ 直到堆中有数据为止

代码表示如下

class Solution {
public:static bool Less(vector<int>& v1 , vector<int>& v2){return v1[0] < v2[0];}int maxEvents(vector<vector<int>>& events) {sort(events.begin() , events.end() , Less);priority_queue<int , vector<int> , greater<int>> pq;int date = 1;int count = 0;int pointer = 0; while (pq.size() || pointer < events.size()){while (pointer < events.size() && events[pointer][0] <= date){pq.push(events[pointer][1]);pointer++;}if (pq.size()){count++;pq.pop();while(pq.size() && pq.top() == date){pq.pop();}}date++;}return count;}
};

切棍子的最小成本

有一根长度为 n 个单位的木棍,棍上从 0 到 n 标记了若干位置。例如,长度为 6 的棍子可以标记如下:

在这里插入图片描述
现在我们给定一个数组 数组格式如下 3 2 1 或者 2 2 2 2

总之 该数组的和一定为木棍的长度 现在告诉你 每次切割木棍要花费的代价为木棍的长度 要求怎么样切割花费的代价最小

这道题目的解题代码很简单 但是思路证明很难 还是一样 我们只给出代码思路 对于证明思路有兴趣的同学可以自己去研究

我们数组中所有的数加入到一个小根堆中 设置一个总代价sum

当小根堆的元素大于2的时候 我们每次取出两个元素相加 sum加上这两个元素后 将这两个元素相加后的值再次放进小根堆中

最后我们得到的结果sum就是答案了

IPO

假设 力扣(LeetCode)即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。

给你 n 个项目。对于每个项目 i ,它都有一个纯利润 profits[i] ,和启动该项目需要的最小资本 capital[i] 。

最初,你的资本为 w 。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。

总而言之,从给定项目中选择 最多 k 个不同项目的列表,以 最大化最终资本 ,并输出最终可获得的最多资本。

这个的贪心我相信大家能够很轻松的想出来 思路如下

  • 我们首先找到我们能够参与的项目(需要资金小于等于我们的资金)
  • 之后将这些项目按照利润排序 放到一个大堆中
  • 之后我们做完一个项目之后更新我们的资金 之后找我们能够参与的项目
  • 找到我们能够参与的项目之后 继续放入大堆中 重复上面的操作

这里有一个小细节是 如果我们的初始资金为0 并且没有可以做的项目的话 我们要直接return 0才行

代码表示如下

class Solution {
public:static bool less(const pair<int,int>& kv1 , const pair<int,int>& kv2){return kv1.first < kv2.first; }int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital) {vector<pair<int , int>> v;int sum = w;int count = k;int pointer = 0;// 将项目的资金排序for (int i = 0; i < profits.size() ; i++){v.push_back({capital[i] , profits[i]});}sort(v.begin() , v.end() , less);priority_queue<int> pq;while(count--){while(pointer < v.size()){if (v[pointer].first <= sum){pq.push(v[pointer].second);pointer++;}else {break;}}if (pq.empty()){return sum;}sum += pq.top();pq.pop();}return sum;}
};

灯塔问题

有一排灯塔,每个灯塔都有一盏灯,每盏灯可以照亮相邻的两个范围(左边一个和右边一个),但是不能跨过其他灯塔。现在给你一个由字符’X’和’.'组成的字符串,‘X’表示灯塔,’.'表示空地。请你计算最少需要打开多少盏灯,才能让所有的灯塔都被照亮

这也是一个典型的贪心问题

我们的解题思路如下

  • 从头开始遍历整个字符串
  • 如果遇到了空地 我们不管他
  • 如果遇到了灯塔 我们查看灯塔后面的一个元素是什么
  • 如果是空地 则我们开灯并且跳跃到空地后一个元素
  • 如果是灯塔 那么我们开启后面一个灯塔 并且跳跃着开启灯塔后面的两个位置

代码也很简单 这里就不给出了

总结下 贪心算法并没有一个固定的套路 只能多做 你做过了你就会 你不做你就不会

证明的思路我们不必去一步步验证 对数器能过就说明我们的思路是正确的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/183330.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python图像处理 ——图像锐化

python图像处理 ——图像锐化 前言一、原理二、 空间域锐化滤波1.拉普拉斯算子&#xff08;Laplacian&#xff09;2.罗伯茨算子&#xff08;Roberts&#xff09;3.Sobel算子4.Prewitt算子5.Scharr算子 三、实验对比 前言 由于收集图像数据的器件或传输图像的通道存在一些质量缺…

【C/C++】什么是POD(Plain Old Data)类型

2023年11月6日&#xff0c;周一下午 目录 POD类型的定义标量类型POD类型的特点POD类型的例子整数类型&#xff1a;C 风格的结构体&#xff1a;数组&#xff1a;C 风格的字符串&#xff1a;std::array:使用 memcpy 对 POD 类型进行复制把POD类型存储到文件中&#xff0c;并从文…

idea中配置spring boot单项目多端口启动

参照文章 https://zhuanlan.zhihu.com/p/610767685 项目配置如下 下面为 idea 2023&#xff0c;不同版本的设置有区别&#xff0c;但是没那么大&#xff0c;idea 2023默认使用新布局&#xff0c;切换为经典布局即可。 在项目根目录的.idea/workspace.xml文件里添加如下配置 &l…

紫光同创FPGA编写的8画面分割器演示

适用于板卡型号&#xff1a; 紫光同创PGL50H开发平台&#xff08;盘古50K开发板&#xff09; 图(1) 盘古50K开发板 TOP 层逻辑框 图(2) TOP层逻辑框 video_copy_ux 将输入的一路RGB888信号复制成8份&#xff0c;每份画面内容相同&#xff0c;各路颜色有些差异&#xff1a; 第…

Linux重定向和缓冲区

文章目录 知识回顾&取地址重定向 重定向底层文件描述符分配规则dup2标准输出和标准错误的区别 缓冲区缓冲区总结 知识回顾 我们在之前有了解过输出重定向>, >>,可以让echo命令本来是打印到屏幕上而变成了把这些数据写到文件中&#xff0c;并且可以追加或者覆盖文…

力扣370周赛 -- 第三题(树形DP)

该题的方法&#xff0c;也有点背包的意思&#xff0c;如果一些不懂的朋友&#xff0c;可以从背包的角度去理解该树形DP 问题 题解主要在注释里 //该题是背包问题树形dp问题的结合版&#xff0c;在树上解决背包问题 //背包问题就是选或不选当前物品 //本题求的是最大分数 //先转…

HTML_案例1_注册页面

用纯html页面&#xff0c;不用css画一个注册页面。 最终效果如下&#xff1a; html页面代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>注册页面</title> </head>…

明御安全网关任意文件上传漏洞复现

简介 安恒信息明御安全网关(NGFW) 秉持安全可视、简单有效的理念&#xff0c;以资产为视角的全流程防御的下一代安全防护体系&#xff0c;并融合传统防火墙、入侵防御系统、防病毒网关、上网行为管控、VPN网关、威胁情报等安全模块于一体的智慧化安全网关。 较低版本的系统存…

Vue、fabricJS 画布实现自由绘制折线

作者GitHub&#xff1a;https://github.com/gitboyzcf 有兴趣可关注 Vue3代码&#xff0c;Vue2相似改吧改吧 前言 Fabric.js Fabric.js&#xff08;英文官网&#xff09;是一个强大而简单的 Javascript HTML5画布库&#xff08;也就是针对canvas进行的封装操作&#xff0c;使…

CentOS/RHEL7环境下更改网卡名称为CentOS6的传统命名规则

图片 CentOS/RHEL7网卡命名规则介绍 图片 传统的Linux服务器网卡的名称命名方式是从eth0,eth1,eth2....这种方式命名的&#xff0c;但是这个编号往往不一定准确对应网卡接口的物理顺序&#xff0c;常规模式下我们使用的服务器设备可能只有一张网卡&#xff0c;若网卡较多的情…

2023年中国金融控股公司研究报告

第一章 行业概况 1.1 定义 金融控股公司这一术语最初源自美国&#xff0c;特别是在美国的《金融服务法案》关于银行控股公司组织结构的条文中&#xff0c;首次出现了“金融控股公司”&#xff08;Financial Holding Company&#xff09;这一法律术语&#xff0c;尽管法案中并…

Flink SQL DataGen Connector 示例

Flink SQL DataGen Connector 示例 1、概述 使用 Flink SQL DataGen Connector&#xff0c;可以快速地生成符合规则的测试数据&#xff0c;可以在不依赖真实数据的情况下进行开发和测试。 2、使用示例 创建一个名为 “users” 的表&#xff0c;包含 6 个字段&#xff1a;id…

力扣 138. 随机链表的复制

题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的…

newstarctf2022week2

Word-For-You(2 Gen) 和week1 的界面一样不过当时我写题的时候出了个小插曲 连接 MySQL 失败: Access denied for user rootlocalhost 这句话印在了背景&#xff0c;后来再进就没了&#xff0c;我猜测是报错注入 想办法传参 可以看到一个name2,试着传参 发现有回显三个字段…

ESP-IDF-V5.1.1使用websocket

IDF Component Registry (espressif.com) 在windows系统中&#xff0c;在项目目录下使用命令 idf.py add-dependency "espressif/esp_websocket_client^1.1.0"

【手册上新】迅为RK3588开发板多屏显示手册

iTOP-RK3588开发板采用四核Cortex-A76处理器和Cortex-A55架构&#xff0c;芯片内置VOP控制器&#xff0c;最多可以支持7个屏幕显示&#xff0c;支持HDMI、LVDS、MIPI、EDP四种显示接口的多屏同显、异显和异触&#xff0c;可有效提高行业定制的拓展性。 iTOP-RK3588开发板支持以…

Java中访问修饰符

类和类之间的关系有如下几种: 以Hero为例自身&#xff1a;指的是Hero自己同包子类&#xff1a;ADHero这个类是Hero的子类&#xff0c;并且和Hero处于同一个包下不同包子类&#xff1a;Support这个类是Hero的子类&#xff0c;但是在另一个包下同包类&#xff1a; GiantDragon 这…

EasyExcel实现动态表头功能

EasyExcel实现动态表头功能 开发过程中&#xff0c;大部分都会使用到导出报表功能&#xff0c;目前阶段会用得有 poi导出&#xff08;暂无&#xff09;&#xff0c; easyexcel导出&#xff08;官方文档&#xff0c;https://easyexcel.opensource.alibaba.com/docs/current/&am…

Linux 实现原理 — NUMA 多核架构中的多线程调度开销与性能优化

前言 NOTE&#xff1a;本文中所指 “线程” 均为可执行调度单元 Kernel Thread。 NUMA 体系结构 NUMA&#xff08;Non-Uniform Memory Access&#xff0c;非一致性存储器访问&#xff09;的设计理念是将 CPU 和 Main Memory 进行分区自治&#xff08;Local NUMA node&#x…