【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.mzph.cn/news/75626.shtml

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

相关文章

【docker】私有仓库搭建

Docker 私有仓库搭建 在 Docker 中&#xff0c;当我们执行 docker pull xxx 的时候 &#xff0c;它实际上是从 registry.hub.docker.com 这个地址去查找&#xff0c;这就是Docker公司为我们提供的公共仓库。在工作中&#xff0c;我们不可能把企业项目push到公有仓库进行管理。…

C高级 第四天

#!/bin/bash#1.实现一个对数组求和的函数,数组通过实参传递给函数 read -p "输入数组" -a arr sum0 function add() {for i in ${arr[*]}do((sumi))done } add arr echo $sum#2.写一个函数,输出当前用户的uid和gid,并使用变量接收结果 function my_id() {num1id -unu…

WebDAV之π-Disk派盘 + 小书匠

小书匠是一款功能丰富,强大的知识管理工具。全平台覆盖,离线数据存储,自定义数据服务器,所见即所得的 markdown 编辑体验。 小书匠提供了多种实用的编辑模式,例如:栏编辑、双栏编辑、三栏编辑、全屏写作、全屏阅读等。并且该软件还提供了许多有用的扩展语法,比如Latex公…

安装vCenter6.7出错 DNS服务原因

https://blog.csdn.net/seaship/article/details/107045006**&#xff21;.VCSA6.7的安装**第1步&#xff0c;运行VCSA 6.7部署程序&#xff0c;中间一些截图参考何老师相关部署文章即可第2步&#xff0c;配置VCSA虚拟机网络&#xff0c;FQDN填写虚拟机分配的IP地址&#xff0c…

SQLite3 操作命令以及c/c++编程API和例子

文章目录 数据库系统SQLiteSQLite数据类型SQLite语句介绍表的创建和查看表的删除插入和修改表数据的删除复制表和修改表结构事务处理函数操作数据分组group by约束联结表视图view触发器trigger日志操作索引 index SQLite c/c编程sqlite3_opensqlite3_closesqlite3_execsqlite3_…

机器人抓取检测技术的研究现状

1.分析法 图 1 为分析法在进行抓取检测时所采用的 一般策略[3] [3]Sahbani A, El-Khoury S, Bidaud P. An overview of 3D object grasp synthesis algorithms[J]. Robotics and Autonomous Systems, 2012, 60(3): 326-336. 首先,基于环境限制和机械手与物体模 型进行抓取检…

2023.9.8 基于传输层协议 UDP 和 TCP 编写网络通信程序

目录 UDP 基于 UDP 编写网络通信程序 服务器代码 客户端代码 TCP 基于 TCP 编写网络通信程序 服务器代码 客户端代码 IDEA 打开 支持多客户端模式 UDP 特点&#xff1a; 无连接性&#xff1a;发送端和接收端不需要建立连接也可相互通信&#xff0c;且每个 UDP 数据包都…

行业追踪,2023-09-11

自动复盘 2023-09-11 凡所有相&#xff0c;皆是虚妄。若见诸相非相&#xff0c;即见如来。 k 线图是最好的老师&#xff0c;每天持续发布板块的rps排名&#xff0c;追踪板块&#xff0c;板块来开仓&#xff0c;板块去清仓&#xff0c;丢弃自以为是的想法&#xff0c;板块去留让…

JVM系列 运行时数据区

系列文章目录 第一章 运行区实验 文章目录 系列文章目录前言一、堆&#xff08;Heap&#xff09;1.1、新生代/Young区1.1.1、Eden区1.1.2、Survival区 1.2、年老代&#xff08;old区&#xff09; 二、虚拟机栈&#xff08;Stack&#xff09;2.1、栈顶缓存技术2.2、溢出2.3、栈…

82 # koa-bodyparser 中间件的使用以及实现

准备工作 安装依赖 npm init -y npm i koakoa 文档&#xff1a;https://koajs.cn/# koa 中不能用回调的方式来实现&#xff0c;因为 async 函数执行的时候不会等待回调完成 app.use(async (ctx, next) > {console.log(ctx.path, ctx.method);if (ctx.path "/login…

C高级day4

一、实现一个对数组求和的函数&#xff0c;数组通过实参传递给函数 二、写一个函数&#xff0c;输出当前用户的uid和gid&#xff0c;并使用变量接收结果 三、XMind思维导图

JavaScript学习--Day04

元字符 边界符&#xff1a; /^/&#xff1a;以什么开头 /$/&#xff1a;以什么结尾 量词&#xff1a; 预定义类&#xff1a;

vs2019配置sfml外部库出现的问题

问题描述 在debug模式下程序正常运行&#xff0c;在release模式中报错 解决 C/C Windows环境下 boost 安装使用教程 Debug 通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不作任何优化&#xff0c;便于程序员调试程序。 Release&#xff1a;Release通常称为发…

基于springboot+vue的实验室耗材管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【业务功能篇105】 微服务-springcloud-springboot-电商订单模块--秒杀服务-定时任务【上篇】

秒杀服务 一、商品上架 秒杀活动的结构图 通过定时任务触发&#xff1a; 定时任务由spring提供&#xff0c;需要通过注解开启&#xff0c;这里通过定义一个配置类&#xff0c;注入spring,对其配置类进行相应的注解&#xff0c;当然也可以注解放在我们的服务启动类上cron表达…

Windows wsl2安装Ubuntu

wsl&#xff08;Windows Subsystem for Linux&#xff09;即适用于Windows的Linux子系统&#xff0c;是一个实现在Windows 10 / 11上运行原生Linux的技术。 wsl2 为其迭代版本&#xff0c;可以更好的在Windows上运行Linux子系统。 这里以 Windows 11 安装Ubuntu作为示例。 开启…

提升效率:PostgreSQL准确且快速的数据对比方法

作为一款强大而广受欢迎的开源关系型数据库管理系统&#xff0c;PostgreSQL 在数据库领域拥有显著的市场份额。其出色的可扩展性、稳定性使其成为众多企业和项目的首选数据库。而在很多场景下&#xff08;开发|生产环境同步、备份恢复验证、数据迁移、数据合并等&#xff09;&a…

“JSR303和拦截器在Java Web开发中的应用与实践“

目录 引言JSR303什么是JSR303?为什么要使用JSR303?常用注解快速入门JSR303 拦截器什么是拦截器拦截器与过滤器应用场景快速入门拦截器 总结 引言 在Java Web开发过程中&#xff0c;我们经常会遇到需要对输入数据进行验证和处理&#xff0c;同时需要对请求进行拦截与控制的需…

PyTorch深度学习实践1——线性回归和Logistic回归

PyTorch的风格 准备数据集使用类设计模型计算损失函数和优化器训练【前向、反向和更新】 线性回归 import torch# 准备数据集 # x,y是矩阵&#xff0c;3行1列 也就是说总共有3个数据&#xff0c;每个数据只有1个特征 x_data torch.tensor([[1.0], [2.0], [3.0]]) y_data to…

Modelsim仿真问题解疑二:ERROR: [USF-ModelSim-70]

现象&#xff1a;在Vivado中已配置modelsim为仿真工具后&#xff0c;运行仿真&#xff0c;报错USF-ModelSim-70和ERROR: [Vivado 12-4473] 详细报错内容如下 ERROR: [USF-ModelSim-70] compile step failed with error(s) while executing C:/Users/ZYP_PC/Desktop/verilog_t…