算法训练营day29 贪心算法③ 134. 加油站、135. 分发糖果 、860.柠檬水找零、406.根据身高重建队列

        贪心算法的第三篇博客,继续脑筋风暴!

134. 加油站

写在前面

        这道题规定了有解的话,必定为唯一解

贪心思路

直接从全局进行贪心选择,情况如下:

  • 情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的

  • 情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。

  • 情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。

        这种解法其实说不出是什么方法,这就是一个从全局角度选取最优解的模拟操作。

class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:curSum = 0  # 当前累计的剩余油量minFuel = float('inf')  # 从起点出发,油箱里的油量最小值for i in range(len(gas)):rest = gas[i] - cost[i]curSum += restif curSum < minFuel:minFuel = curSumif curSum < 0:return -1  # 情况1:整个行程的总消耗大于总供给,无法完成一圈if minFuel >= 0:return 0  # 情况2:从起点出发到任何一个加油站时油箱的剩余油量都不会小于0,可以从起点出发完成一圈for i in range(len(gas) - 1, -1, -1):rest = gas[i] - cost[i]minFuel += restif minFuel >= 0:return i  # 情况3:找到一个位置使得从该位置出发油箱的剩余油量不会小于0,返回该位置的索引return -1  # 无法完成一圈

贪心算法的另外一种理解

        其实核心内容和上面的方法是一样的,不过是没有计算总油量盈余,转而使用负数逼近的方法:

        i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起(重新作为起点),再从0计算curSum。

class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:curSum = 0  # 当前累计的剩余油量totalSum = 0  # 总剩余油量start = 0  # 起始位置for i in range(len(gas)):curSum += gas[i] - cost[i]totalSum += gas[i] - cost[i]if curSum < 0:  # 当前累计剩余油量curSum小于0start = i + 1  # 起始位置更新为i+1curSum = 0  # curSum重新从0开始累计if totalSum < 0:return -1  # 总剩余油量totalSum小于0,说明无法环绕一圈return start

for循环——常规思路

        挨个作为起点累加计算,未出现负数即ok

class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:for i in range(len(cost)):rest = gas[i] - cost[i]  # 记录剩余油量index = (i + 1) % len(cost)  # 下一个加油站的索引while rest > 0 and index != i:  # 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)rest += gas[index] - cost[index]  # 更新剩余油量index = (index + 1) % len(cost)  # 更新下一个加油站的索引if rest >= 0 and index == i:  # 如果以i为起点跑一圈,剩余油量>=0,并且回到起始位置return i  # 返回起始位置ireturn -1  # 所有起始位置都无法环绕一圈,返回-1

135. 分发糖果

        本题采用了两次贪心的策略:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

        这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。

class Solution:def candy(self, ratings: List[int]) -> int:n = len(ratings)candies = [1] * n# Forward pass: handle cases where right rating is higher than leftfor i in range(1, n):if ratings[i] > ratings[i - 1]:candies[i] = candies[i - 1] + 1# Backward pass: handle cases where left rating is higher than rightfor i in range(n - 2, -1, -1):if ratings[i] > ratings[i + 1]:candies[i] = max(candies[i], candies[i + 1] + 1)return sum(candies)

860.柠檬水找零

        本以为累加即可,但其实是不对的,因为存在10美分和5美分的区别,所以不能混为一谈

        局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。

        这道题告诉我们,不要总是想判断总数,可以把每个单独的数字列成参数,分别处理

class Solution:def lemonadeChange(self, bills: List[int]) -> bool:five = 0ten = 0twenty = 0for bill in bills:# 情况一:收到5美元if bill == 5:five += 1# 情况二:收到10美元if bill == 10:if five <= 0:return Falseten += 1five -= 1# 情况三:收到20美元if bill == 20:# 先尝试使用10美元和5美元找零if five > 0 and ten > 0:five -= 1ten -= 1#twenty += 1# 如果无法使用10美元找零,则尝试使用三张5美元找零elif five >= 3:five -= 3#twenty += 1else:return Falsereturn True

406.根据身高重建队列

        重点理解排序!这两个排序很重要!

class Solution:def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:# 默认升序# -x[0]:对第一个值取负,实现降序排列(数值越大越靠前)。# x[1]:第二个值保持原值,实现升序排列(数值越小越靠前)。people.sort(key=lambda x: (-x[0], x[1]))que = []# 具体是先处理身高较高的,在身高相同的情况下,优先处理 k 值较小的。# 这两个排序必不可少!!# 因为身高已经是高->低, 低对高无影响, 所以低身高直接根据K值插入即可# 同时相同K值, 需要从低->高依次处理, 因为后面的插入必须要在大索引的位置, 不能影响之前插入的元素for p in people:que.insert(p[1], p)# list.insert(index, element)# index:插入位置的索引# element:要插入的元素return que

底层实现补充(C++)

        使用vector是非常费时的,C++中vector(可以理解是一个动态数组,底层是普通数组实现的)如果插入元素大于预先普通数组大小,vector底部会有一个扩容的操作,即申请两倍于原先普通数组的大小,然后把数据拷贝到另一个更大的数组上。

        所以使用vector(动态数组)来insert,是费时的,插入再拷贝的话,单纯一个插入的操作就是O(n^2)了,甚至可能拷贝好几次,就不止O(n^2)了。

        可以使用链表代替

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

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

相关文章

【09】C#入门到精通——C# 结构体对齐 与 常用数据 对应关系

文章目录1 C# 结构体对齐1.1 默认对齐方式1.2 节对齐方式设置1.3 偏移量设置2 C#与C/C之间类型的对应关系1 C# 结构体对齐 1.1 默认对齐方式 struct默认对齐方式&#xff0c;结构体长度必须是&#xff0c;最大成员长度的整数倍&#xff0c;所以下面结构体大小是 24 (实际占用…

pytest 测试报告生成方案有哪些?

在 pytest 中&#xff0c;除了 Allure 和 HTMLTestRunner&#xff0c;还有许多其他生成测试报告的方法和插件。以下是一些常用的方案及其特点&#xff1a;1. pytest-html&#xff08;官方推荐&#xff09;特点&#xff1a;轻量级、易集成&#xff0c;生成独立的 HTML 报告。安装…

Unity中EditorPrefs与PlayerPrefs对比分析

Unity中EditorPrefs与PlayerPrefs对比分析 EditorPrefs与PlayerPrefs是Unity引擎中用于数据持久化的两个核心类&#xff0c;分别用于于编辑器扩展与游戏运行时场景。以下从设计目标、存储位置、数据类型、生命周期、安全性、使用场景等方面展开对比&#xff0c;并结合代码示例说…

蓝光中的愧疚

蓝光中的愧疚活动结束那晚&#xff0c;深圳的空气吸饱了水汽&#xff0c;沉甸甸地压在胸口。我站在西乡社区活动中心冰凉的玻璃门外&#xff0c;目送着最后一个离开的王老师。她关掉门厅的灯&#xff0c;电子门锁合拢时发出轻微却尖锐的“嘀”声&#xff0c;像一根细针扎在我紧…

Linux: network: wireshark: esp attempt to detec null-encrypted esp payloads

最近看到一个pcap文件&#xff0c;里面有esp协议包&#xff0c;而且是明文/没有加密的消息&#xff0c;为什么wireshark没有将esp上层的tcp/sip消息没有解出来。 类似于Info列只有ESP的信息。后来选中了协议选项里的&#xff1a;attempt to detect/decode NULL encrypted ESP p…

10分钟搭建脚手架:Spring Boot 3.2 + Vue3 前后端分离模板

10分钟搭建脚手架&#xff1a;Spring Boot 3.2 Vue3 前后端分离模板一、项目结构设计二、后端搭建&#xff08;Spring Boot 3.2&#xff09;1. 快速初始化&#xff08;使用 Spring Initializr&#xff09;2. 核心配置application.yml跨域配置 CorsConfig.java3. 安全配置Secur…

【轨物方案】分布式光伏电站运维升级智能化系列:老电站的数智化重生

自2010年分布式光伏在国内兴起以来&#xff0c;十余年间&#xff0c;市场装机容量已实现飞跃式增长。长期以来&#xff0c;传统的人工巡查和抄表模式是它们日常运维的主要手段。然而&#xff0c;随着电站数量的激增和设备的老化&#xff0c;由此导致的事故频发&#xff0c;使得…

RAG 技术深度面试题:架构、优化与实践应用

1. RAG 基础架构设计 问题&#xff1a;对比单阶段检索&#xff08;Single-stage Retrieval&#xff09;与两阶段检索&#xff08;Two-stage Retrieval&#xff09;在 RAG 系统中的架构差异&#xff0c;说明在企业知识库场景下为何优先选择两阶段检索&#xff1f; 答案&#xff…

yolov8通道级剪枝讲解(超详细思考版)

为了提升推理速度并降低部署成本&#xff0c;模型剪枝已成为关键技术。本文将结合实践操作&#xff0c;讲解YOLOv8模型剪枝的方法原理、实施步骤及注意事项。 虽然YOLOv8n版本本身参数量少、推理速度快&#xff0c;能满足大多数工业检测需求&#xff0c;但谷歌研究表明&#x…

JavaSE:随机数生成

随机数在游戏开发、密码学、模拟测试等场景中扮演着关键角色。本文将深入探讨Java中两种主流的随机数生成技术&#xff1a;Random类和Math.random()方法&#xff0c;并解析背后的类与对象概念&#xff0c;助你全面掌握随机数生成的核心机制。一、随机数生成的两大技术 Java提供…

Android 持久化存储原理与使用解析

一、核心存储方案详解1. SharedPreferences (SP)使用方式&#xff1a;// 获取实例 SharedPreferences sp getSharedPreferences("user_prefs", MODE_PRIVATE);// 写入数据 sp.edit().putString("username", "john_doe").putInt("login_cou…

无 sudo 权限的环境下将 nvcc (CUDA Toolkit) 安装到个人目录 linux

要在无 sudo 权限的环境下将 nvcc 安装到 home 个人目录&#xff0c;你可以手动安装 CUDA Toolkit 到你的 $HOME 目录&#xff0c;只需以下几步即可使用 nvcc 编译 CUDA 程序。 ✅ 步骤&#xff1a;本地安装 CUDA Toolkit&#xff08;含 nvcc&#xff09; 下载 CUDA Toolkit Ru…

从指标定义到AI执行流:衡石SENSE 6.0的BI PaaS如何重构ISV分析链路

一、痛点&#xff1a;ISV行业解决方案的“三重断链”传统ISV构建行业分析模块时面临的核心挑战&#xff1a;指标定义碎片化&#xff1a;客户A的“销售额”含税&#xff0c;客户B不含税&#xff0c;衍生指标无法复用&#xff1b;分析-执行割裂&#xff1a;发现库存异常后需人工导…

构建跨平台远程医疗系统中的视频通路技术方案探究

一、远程医疗走向日常化&#xff0c;音视频能力成为关键基础设施 随着医疗数字化与分级诊疗体系的不断演进&#xff0c;远程医疗正从试点探索阶段&#xff0c;逐步迈向常态化、标准化应用。从县域医院远程问诊、基层医疗协作&#xff0c;到大型三甲医院的术中协同、专科教学直…

Blackbox Exporter Docker 安装配置,并与 Prometheus 集成

1. 创建配置文件目录bashmkdir -p ~/docker/blackbox/config cd ~/docker/blackbox2. 创建 Blackbox Exporter 配置文件 config/blackbox.ymlyamlmodules:http_2xx: # HTTP 可用性检测(响应 2xx/3xx 状态码)prober: httphttp:valid_http_versions: ["HTTP/1.1", &qu…

杰理通用MCU串口+AT指令+485通讯工业语音芯片

一、概述 在现代智能设备与自动化系统中&#xff0c;语音交互功能日益普及&#xff0c;通用 MCU 语音芯片作为核心组件&#xff0c;承担着关键的语音处理任务。其强大的功能不仅体现在语音合成、识别等方面&#xff0c;还包括高效的通信能力。串口 AT 指令 485 通讯模式为通用…

Krpano 工具如何调节全景图片切割之后的分辨率

文章目录概要第一步1.1 复制一下这个文件中的key &#xff0c;打开 krpano Tools.exe第二步 修改切片之后的分辨率修改前的效果修改后的效果概要 前端渲染全景图模拟3D场景 Krpano 工具 获取到后的默认图片分辨率是2048*2048的&#xff0c;如果觉得分辨率低了可以自行在工具中…

物联网十大应用领域深度解析

一、智能物流技术基础&#xff1a;RFID、无线传感器网络、互联网与运筹学、供应链管理理论结合 应用场景&#xff1a;仓储管理&#xff1a;RFID标签实现库存实时监控&#xff0c;自动补货系统降低缺货率。配送优化&#xff1a;通过GPS与物联网数据分析规划最优路径&#xff0c;…

ElasticSearch基础数据查询和管理详解

目录 一、 ElasticSearch核心概念 1. 全文搜索&#xff08;Full-Text Search&#xff09; 2. 倒排索引&#xff08;Inverted Index&#xff09; 3. ElasticSearch常用术语 3.1 映射&#xff08;Mapping&#xff09; 3.2 索引&#xff08;Index&#xff09; 3.3 文档&…

SSE与Websocket有什么区别?

SSE&#xff08;Server-Sent Events&#xff09;和WebSocket都能实现服务器与客户端的实时通信&#xff0c;但它们在协议设计、应用场景和技术特性上有明显差异。以下从多个维度对比两者的区别&#xff1a; 1. 协议基础 SSE 基于HTTP协议&#xff0c;是HTTP的扩展。使用单向通…