贪心算法总结及其leetcode题目N道
1 我为什么要写这个总结
1.1 字节笔试题
小明在玩一场通关游戏,初始血量为1,关卡有怪兽或者有血包(正数就是血包可回血数,负数说明是怪兽的伤害值),当捡到血包时会加血量,碰到怪兽时会掉血,现在指定初始血量为x,关卡是一个数组,小明必须按照数组的顺序玩游戏,当碰到一个怪兽时,他可以选择将这个怪兽扔到数组末尾,小明可以无限次地将怪兽移到数组末尾,问小明最少移动几次就能存活,如果无论怎么移动都不能存活则返回-1, 假设关卡是这样的[-200,-300,400],则返回-1,假如是这样的[200,100,-250,-60,-70,100],则返回1,只需要把-250挪到尾部,
思路:当发现自己血量不足时,就从当前已经遍历过的所有关卡中,选择耗费血量最多的那个关卡并且放到最后一关,如果即使这样挪开了耗血量最大的一关自身血量还是为负,则直接返回-1,说明无法通关
2 总结
2.1 什么是局部最优?
贪心关注的是局部最优,这里当前最优(指当前遍历的所有元素中的最优解)也是局部最优的一种,而一般的最有解又涉及到数据的最值,而且随着元素的不断向右扩展,可能这个最优值是不断变化的,所以一般可以使用堆来动态维护它的最值。
2.2 解贪心类题目的一些分类
分为相向双指针,同向双指针以及最值堆等类型
2.2.1 相向双指针和同向双指针的解题思路的区别
-
相向双指针通常用于处理排序数组中的问题,比如找出两个数的和等于特定值(如LeetCode题目167. 两数之和 II - 输入有序数组),或者反转数组(如LeetCode题目344. 反转字符串)。对于这类问题,两个指针分别从数组的头部和尾部出发,根据指向元素的大小关系向中间移动,直到两个指针相遇。
-
同向双指针通常用于处理数组或字符串中需要连续元素满足特定条件的问题,比如找出满足特定和的最小子数组(如LeetCode题目209. 长度最小的子数组),或者找出最长的满足特定条件的子串(如LeetCode题目424. 替换后的最长重复字符)。对于这类问题,一个指针(快指针)用于遍历数组或字符串,另一个指针(慢指针)用于维护满足条件的区间。
2.2.2 在LeetCode上,与同向双指针和贪心策略相关的题目有很多。举两个例子:
-
题目 209. 长度最小的子数组: 在一个正整数数组中寻找长度最小的连续子数组,其和至少为特定值。解决这个问题的方法是维持一个滑动窗口,窗口的左右边界就是同向的双指针。右指针向右移动以增加子数组的和,当子数组的和达到或超过目标值时,尝试将左指针向右移动以减小子数组的长度。
-
题目 424. 替换后的最长重复字符: 给定一个字符串和一个整数k,找出可以通过最多替换k个字符以得到的最长的重复字符子串。解决这个问题的方法同样是维持一个滑动窗口,窗口的左右边界就是同向的双指针。右指针向右移动以增加子串的长度,当子串中最多的字符数量加上k小于子串的长度时,左指针向右移动。
2.3 一部分需要预处理的题目
2.3.1 可能需要排序
- 分发饼干
2.3.2 可能需要hashMap统计字符最后一次出现的位置
- 划分字母区间
3 使用堆解决问题的贪心策略
3.1 leetcode1046. 最后一块石头的重量
3.2 leetcode 1642. 可以到达的最远建筑
leetcode 1642. 可以到达的最远建筑
标准答案:
// 砖块优先,砖块数量不足时考虑将当前替代最小高度的梯子改用砖块替代public int furthestBuilding(int[] heights, int bricks, int ladders) {int n=heights.length;//大根堆PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o2-o1));int i;int sum=0;//表示当前需要的梯子数量int sum_bri=0;for(i=1;i<n;i++){int diff=heights[i]-heights[i-1];if(diff>0){pq.offer(diff);sum_bri+=diff;//砖块的数量之和if(sum_bri>bricks){sum_bri-=pq.poll();sum++;}if(sum>ladders){return i-1;}}}return n-1;}//每次先放梯子,当梯子数量不足时,将当前使用过的梯子中,替代阶梯数最少的梯子找出来用对应砖头替换,替换出来的梯子拿到当前使用public int furthestBuilding(int[] heights, int bricks, int ladders) {int n=heights.length;//int[]:PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o1-o2));int i;int sum=0;//表示当前需要的砖块数量for(i=1;i<n;i++){int diff=heights[i]-heights[i-1];if(diff>0){pq.offer(diff);if(pq.size()>ladders){sum+=pq.poll();}if(sum>bricks){return i-1;}}}return n-1;}```我的答案:(有几个特别长的case过不了)```java
public int furthestBuilding2(int[] heights, int bricks, int ladders) {int n=heights.length;PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o1-o2));int i;for(i=1;i<n;){int diff=heights[i-1]-heights[i];// System.out.println("i:"+i+",diff:"+diff+",heights[i-1]:"+heights[i-1]+",heights[i]:"+heights[i]);if(diff<0){int diffAbs=-diff;if(ladders>0){ladders--;pq.add(diffAbs);}else if(bricks>=diffAbs){bricks-=diffAbs;}else{int newd=Integer.MAX_VALUE;if(!pq.isEmpty()){newd=pq.peek();}if(bricks>=newd){pq.poll();bricks-=newd;ladders++;i=i-1;}else{break;}}}i++;}return i-1;}
这里还有一个二分查找的方法:
每太整明白:
3.3 121. 买卖股票的最佳时机(虽然使用堆的方法不是最优解,但是方便和其他题目对比得出最优解)
3.3.1 这个题和3.1以及3.2有什么异同呢?
同:都涉及到取最值,而且最值都是可能变化的
不同:3.1以及3.2中的题目一个最值只能使用一次,一旦使用就得poll操作,而本题中的最值可以复用。正式这个特性导致了前者只能使用堆来维护最值(因为可能需要多次取最值,即使用到多个最值,poll操作只能靠堆维护),虽说本题也多次最最值,但是可以重用最值,没有poll操作。
class Solution {// 使用堆维护最小值public int maxProfit(int[] prices) {int n=prices.length;//表示到第i天时,股票的历史最低点价格PriorityQueue<Integer>pq=new PriorityQueue<>((o1,o2)->(o1-o2));int max=0;for(int i=0;i<n;i++){pq.add(prices[i]);max=Math.max(max,prices[i]-pq.peek());}return max;}// 方法:使用dp维护已经遍历值得最小值public int maxProfit3(int[] prices) {int n=prices.length;//表示到第i天时,股票的历史最低点价格int[]f=new int[n];f[0]=prices[0];int max=0;for(int i=1;i<n;i++){f[i]=Math.min(f[i-1],prices[i]);max=Math.max(max,prices[i]-f[i]);}return max;}// 方法:使用一个变量维护已经遍历值得最小值public int maxProfit(int[] prices) {int n=prices.length;//表示到第i天时,股票的历史最低点价格int min=prices[0];int max=0;for(int i=1;i<n;i++){min=Math.min(min,prices[i]);max=Math.max(max,prices[i]-min);}return max;}// 使用单调栈维护已经遍历序列的最小值public int maxProfit2(int[] prices) {int n=prices.length;Deque<Integer>st=new ArrayDeque<>();int max=0;st.add(prices[0]);for(int i=1;i<n;i++){int p=prices[i];if(!st.isEmpty()&&p<=st.peekLast()){max=Math.max(st.peekLast()-st.peekFirst(),max);while(!st.isEmpty()&&st.peekLast()>=p){st.pollLast();}}st.addLast(p);}if(!st.isEmpty()){max=Math.max(st.peekLast()-st.peekFirst(),max);}return max;}
}
3.3 871题最低加油次数和
3.4 630课程表III
4 使用相向双指针解决问题的贪心策略
4.1 167. 两数之和 II - 输入有序数组
思路:双指针解决偏差
class Solution {public int[] twoSum(int[] numbers, int target) {int n=numbers.length;int i=0,j=n-1;while(i<j){int sum=numbers[i]+numbers[j];if(sum>target){j--;}else if(sum<target){i++;}else{return new int[]{i+1,j+1};}}return new int[]{i+1,j+1};}}
4.2 11. 盛最多水的容器
思路:容器能盛的水取决于短板,不断移动双指针中代表较小数值的那个指针,直到两个指针相遇,其中得到的所有可能的盛水量中取最大值即可。
class Solution {public int maxArea(int[] height) {int n=height.length;int i=0,j=n-1;int max=-1;while(i<j){int s=(j-i)*Math.min(height[i],height[j]);max=Math.max(max,s);if(height[i]>height[j]){j--;}else{i++;}}return max;}
}
5 同向双指针与贪心策略
5.1 763. 划分字母区间(找出数组中满足特定条件的子序列)
class Solution {public List<Integer> partitionLabels(String s) {int n=s.length();int[]mp=new int[26];for(int i=0;i<n;i++){mp[s.charAt(i)-'a']=i;}List<Integer>res=new ArrayList<>();int start=0,end=0;for(int i=0;i<n;i++){end=Math.max(end,mp[s.charAt(i)-'a']);if(end==i){res.add(i-start+1);start=i+1;}}return res;}
}
相关文章:
贪心算法总结及其leetcode题目N道
1 我为什么要写这个总结 1.1 字节笔试题 小明在玩一场通关游戏,初始血量为1,关卡有怪兽或者有血包(正数就是血包可回血数,负数说明是怪兽的伤害值),当捡到血包时会加血量,碰到怪兽时会掉血&am…...
k8s的namespace一直处于terminating的解法
先试了强制替换,无法替换掉,强制删除,也删除不掉namespace [rootmaster k8s-study]# vi ns-demo.yaml [rootmaster k8s-study]# kubectl create -f ns-demo.yaml namespace/demo created [rootmaster k8s-study]# kubectl get -f ns-demo.ya…...

JAVA面试总结-Redis篇章(六)——数据过期策略
Java面试总结-Redis篇章(六)——数据过期策略 Redis数据删除策略——惰性删除Redis数据删除策略——定期删除 Redis数据删除策略——惰性删除 Redis数据删除策略——定期删除...

【LLM】大语言模型学习之LLAMA 2:Open Foundation and Fine-Tuned Chat Model
大语言模型学习之LLAMA 2:Open Foundation and Fine-Tuned Chat Model 快速了解预训练预训练模型评估微调有监督微调(SFT)人类反馈的强化学习(RLHF)RLHF结果局限性安全性预训练的安全性安全微调上手就干使用登记代码下载获取模型转换模型搭建Text-Generation-WebUI分发模型…...
Android是如何识别USB信号的
Android设备通过USB接口与外部设备通信时,会通过USB控制器(USB Controller)与USB设备进行通信。USB控制器是Android设备的一个硬件组件,它负责管理USB总线并控制所有USB设备的连接和通信。 当一个USB设备被插入Android设备的USB接…...
机器学习前言
1.机器学习和统计学关系 2.机器学习的发展 3.机器学习与深度学习的相同点与不同点 4.机器学习和深度学习优缺点 一、机器学习和统计学关系 机器学习和统计学密切相关,可以说机器学习是统计学在计算机科学和人工智能领域的应用。机器学习和统计学在方法论和技术上有…...

Java另一种debug方法(not remote jmv debug),类似python远程debug方式
这种Debug类似python的debug方式,是运行时将业务代码及依赖推送到Linux并使用Linux的java运行运行程。只要本地能运行,就能自动将代码推送到Linux运行,不需打包及设置远程debug jvm参数,适合一些项目Debug调试 运行时会推送一些依…...

【QT】Day4
1> 思维导图 2> 手动完成服务器的实现,并具体程序要注释清楚 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //…...
在CSDN学Golang云原生(Kubernetes Pod 有状态部署)
一,StatefulSet部署MongoDB集群 Kubernetes StatefulSet 是 Kubernetes 中的一种资源类型,它能够保证有状态服务(Stateful Service)的唯一性和顺序部署,适用于需要持久化存储、网络标识、状态管理等场景。MongoDB 是一…...
sql-从一个或多个表中向一个表中插入 多行
INSERT还可以将SELECT语句查询的结果插入到表中,此时不需要把每一条记录的值一个一个输入,只需 要使用一条INSERT语句和一条SELECT语句组成的组合语句即可快速地从一个或多个表中向一个表中插入 多行。 基本语法格式如下: INSERT INTO 目标表…...

ElementUI 实现动态表单数据校验(已解决)
文章目录 🍋前言:🍍正文1、探讨需求2、查阅相关文档([element官网](https://element.eleme.cn/#/zh-CN/component/form))官方动态增减表单项示例3、需求完美解决4、注意事项 🎃专栏分享: &#…...

Linux上定位线上CPU飙高
【模拟场景】 写一个java main函数,死循环打印 System.out.println(“111111”) , 将其打成jar包放在linux中执行 1、通过TOP命令找到CPU耗用最厉害的那个进程的PID 2、top -H -p 进程PID 找到进程下的所有线程 可以看到 pid 为 94384的线程耗用cpu …...

06-行向量列向量_向量的运算 加法,数乘,减法,转置
行向量和列向量 行向量是按行把向量排开(横着来写), 列向量是按列把向量排开(竖着来写) 在数学中我们更多的把数据写成列向量,在编程语言中更多的把数据存成行向量! 如果想在编程语言中把行向量转化成列…...
基于Matlab实现最大类间方差阈值与遗传算法的道路分割(附上完整源码+图像+程序运行说明)
道路分割是计算机视觉和图像处理中的一个重要任务,它在交通监控、自动驾驶和地图制作等领域具有广泛的应用。其中,最大类间方差阈值和遗传算法是道路分割中常用的方法之一。本文将介绍如何使用Matlab实现最大类间方差阈值与遗传算法进行道路分割。 文章目…...

13.4.2 【Linux】sudo
相对于 su 需要了解新切换的使用者密码 (常常是需要 root 的密码), sudo 的执行则仅需要自己的密码即可。sudo 可以让你以其他用户的身份执行指令 (通常是使用 root 的身份来执行指令),因此并非所有人都能够…...

电脑软件:键盘按键修改器——keytweak使用介绍
对你的电脑键盘的布局不满意、键盘上的某个按键坏掉了等等键盘问题如何解决?有了KeyTweak这一切就可以轻松解决了,KeyTweak是一个免费软件程序,使用它可让你重新映射键盘键。如果您改变主意并想将其改回原样,只需点击一下即可容易…...

软件工程学术顶会——ICSE 2023 议题(网络安全方向)清单与摘要
按语:IEEE/ACM ICSE全称International Conference on Software Engineering,是软件工程领域公认的旗舰学术会议,中国计算机学会推荐的A类国际学术会议,Core Conference Ranking A*类会议,H5指数74,Impact s…...
【Python】jupyter Linux服务器使用
文章目录 环境使用访问 环境 pip install jupyter 使用 在你想访问的目录下执行: jupyter notebook --ip0.0.0.0jupyter 给出提示: [I 2023-07-28 14:32:43.589 ServerApp] Package notebook took 0.0000s to import [I 2023-07-28 14:32:43.597 Ser…...

element 级联 父传子
html代码例子 父组件 <el-cascaderstyle"width: 100%"change"unitIdChange":options"unitOptions"filterablev-model"formInline.unitId":props"unitProps"/></el-form-item>//改变级联传值到这个组件里面<r…...

【MTI 6.S081 Lab】Copy-on-write
【MTI 6.S081 Lab】Copy-on-write The problemThe solutionImplement copy-on-write fork (hard)实验任务Hints解决方案问题解决思考uvmcopykfreekallockpagerefcow_handlertrap 虚拟内存提供了一定程度的间接性:内核可以通过将PTE标记为无效或只读来拦截内存引用&a…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...