【Java】HOT100 贪心算法
目录
理论基础
一、简单贪心
LeetCode455:分发饼干
二、中等贪心
2.1 序列问题
LeetCode376:摆动序列
2.2 贪心股票问题
LeetCode121:买卖股票的最佳时机
LeetCode121:买卖股票的最佳时机ii
2.3 两个维度权衡问题
LeetCode135:分发糖果
三、较难问题
区间问题
LeetCode55:跳跃游戏i
LeetCode55:跳跃游戏ii
LeetCode452:用最少数量的箭引爆气球
LeetCode435:无重叠区间
LeetCode763:划分字母区间
LeetCode56:合并区间
其他
LeetCode53:最大子序和
贪心算法其实就是没有什么规律可言,所以大家了解贪心算法 就了解它没有规律的本质就够了。 不用花心思去研究其规律, 没有思路就立刻看题解。基本贪心的题目 有两个极端,要不就是特简单,要不就是死活想不出来。
学完贪心之后再去看动态规划,就会了解贪心和动规的区别。
理论基础
贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
举例:有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿?指定每次拿最大的,最终结果就是拿走最大数额的钱。
每次拿最大的就是局部最优,最后拿走最大数额的钱就是推出全局最优。
再举一个例子如果是 有一堆盒子,你有一个背包体积为n,如何把背包尽可能装满,如果还每次选最大的盒子,就不行了。这时候就需要动态规划。动态规划的问题在下一个系列会详细讲解。
什么时候用贪心呢?没有固定的套路。刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心。
贪心算法一般分为如下四步:
- 将问题分解为若干个子问题
- 找出适合的贪心策略
- 求解每一个子问题的最优解
- 将局部最优解堆叠成全局最优解

一、简单贪心
LeetCode455:分发饼干
思路:这里的局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,
全局最优就是喂饱尽可能多的小孩。
所以可以尝试使用贪心策略,先将饼干数组和小孩数组排序。然后从后向前遍历小孩数组,用大饼干优先满足胃口大的,并统计满足小孩数量。

class Solution {// 思路:优先考虑胃口,先喂饱大胃口public int findContentChildren(int[] g, int[] s) {Arrays.sort(g);Arrays.sort(s);int count = 0;int start = s.length - 1;// 遍历胃口for (int index = g.length - 1; index >= 0; index--) {if(start >= 0 && g[index] <= s[start]) {start--;count++;}}return count;}
}
二、中等贪心
2.1 序列问题
LeetCode376:摆动序列
思路:局部最优是删除连续坡度上的节点,保证这个坡度有两个局部峰值
整体最优是整个序列拥有最多的局部峰值
在实际操作上,实际连删除都不用做,只需添加数组的局部峰值即可
本题的难度在于要考虑多种情况:(curdiff代表后一个坡度,prediff代表前一个坡度)
即单调有平坡、上下中间有平坡和只有两个数的情况,具体分析见代码随想录
class Solution {public int wiggleMaxLength(int[] nums) {if (nums.length <= 1) {return nums.length;}//当前差值int curDiff = 0;//上一个差值int preDiff = 0;int count = 1;for (int i = 1; i < nums.length; i++) {//得到当前差值curDiff = nums[i] - nums[i - 1];//如果当前差值和上一个差值为一正一负//等于0的情况表示初始时的preDiffif ((curDiff > 0 && preDiff <= 0) || (curDiff < 0 && preDiff >= 0)) {count++;preDiff = curDiff;}}return count;}
}
这道题还可以用动态规划来做,这里就不讲了。之后可以试着做一做。
2.2 贪心股票问题
LeetCode121:买卖股票的最佳时机
思路:局部最优即左界最小,在局部最优的基础上要求的全局最优即右界最大,也就是差值最大。
class Solution {public int maxProfit(int[] prices) {int max = 0;int low = Integer.MAX_VALUE; //保留左侧最小值for (int i = 0; i < prices.length; i++) {low = Math.min(low, prices[i]); // 取最左最小价格,确定左界max = Math.max(max, prices[i] - low); // 寻找右侧最大值}return max;}
}
LeetCode121:买卖股票的最佳时机ii
思路:局部最优即在区间中寻找所有的最大递增子区间,且子区间之间不能重叠
整体最优:取所有最大的递增子区间,最后利润和也最大。
由于最后只要求利润,该题可以变成只要收集每天的正利润,而无需考虑区间的左右界。
// 贪心思路
class Solution {public int maxProfit(int[] prices) {int result = 0;for (int i = 1; i < prices.length; i++) {result += Math.max(prices[i] - prices[i - 1], 0);}return result;}
}
2.3 两个维度权衡问题
LeetCode135:分发糖果
思路:本题需要先确定一遍后,在确定另一边,从左到右的局部最优即:只要右边评分比左边大,右边的孩子就多一个糖果。全局最优:评分高的右边孩子比左边孩子糖果更多。
本题需要先从左到右更新,再从右到左,这样才能满足相邻条件。从右到左局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
class Solution {/**分两个阶段1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1,不大于就取最小糖果数1;2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大*/public int candy(int[] ratings) {int len = ratings.length;int[] candyVec = new int[len];candyVec[0] = 1;for (int i = 1; i < len; i++) {candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;}for (int i = len - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) {candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);}}int ans = 0;for (int num : candyVec) {ans += num;}return ans;}
}
三、较难问题
区间问题
LeetCode55:跳跃游戏i
思路:总共要跳nums.length-1步才能到达终点,局部解即取最大跳跃步数max,每次循环以第一轮的max为起点再次计算max的覆盖范围
整体解即所有的最大跳跃步数范围是否能覆盖到终点。
class Solution {public boolean canJump(int[] nums) {int max = 0;for(int i=0;i<=max;i++){ //这里注意是小于等于max,max更新等于以新一轮覆盖点为起点再次覆盖max = Math.max(i+nums[i],max);if(max>=nums.length-1) return true;}return false;}
}
LeetCode55:跳跃游戏ii
思路:局部解即每次的跳转步数尽可能最大,这样跳跃次数就最小
整体解即范围覆盖到终点且跳跃次数最小
本题的关键在于什么时候对步数进行+1?用到两个变量curIndex和preIndex来确定位置
class Solution {public int jump(int[] nums) {int nextIndex = 0;int curIndex = 0;int count = 0;for(int i=0; i<=nums.length;i++){nextIndex = Math.max(nextIndex,i+nums[i]);if(i == curIndex){ //当走到当前的最大覆盖范围时,判断是否到终点count++; //如果没到,就要跳一步curIndex = nextIndex; //跳到更新过的下一坐标if(nextIndex >= nums.length - 1) break; //如果到了则走完了}}return count;}
}
LeetCode452:用最少数量的箭引爆气球
思路:写了435,这道题就很容易了
class Solution {public int findMinArrowShots(int[][] points) {int count = 1;Arrays.sort(points, (x,y)->Integer.compare(x[1],y[1]));int end = points[0][1];for(int i=1;i<points.length;i++){//只要右界排序,记录不重叠的情况就可以了,每次不重叠就需要多一支箭if(end < points[i][0]){ count++;end = points[i][1];}}return count;}
}
LeetCode435:无重叠区间
思路:重叠区间问题通常有两种思路:要么是按左边界排序,要么是按右边界
1. 按右边界升序排列,从左向右可以记录非重叠区间的个数,总数-非重叠个数=重叠个数
非重叠只要判断end和上一区间的左区间的关系

class Solution {public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals, (a,b)-> {return Integer.compare(a[1],b[1]);});int count = 1; //记录非重叠区间的个数int end = intervals[0][1];for(int i = 1;i < intervals.length;i++){if(end <= intervals[i][0]){ //无重叠区间,count++,更新endcount++;end = intervals[i][1];}}return intervals.length-count;}
}
2. 按左边界升序排序,向左到右可以记录重叠的区间个数,直接得到重叠个数就是移除个数
非重叠和重叠都要更新end,之所以count取end和右界的较小值是因为,可能会出现>=3个区间重叠的情况。
class Solution {public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals, (a,b)-> {return Integer.compare(a[0],b[0]);});int count = 0; //记录重叠区间的个数int end = intervals[0][1];for(int i = 1;i < intervals.length;i++){if(end <= intervals[i][0]){ //无重叠区间,更新endend = intervals[i][1];}else{count++;end = Math.min(end, intervals[i][1]); //重叠区间的end}}return count;}
}
LeetCode763:划分字母区间
思路:首先遍历计算每个字母的最后出现下标,然后从头开始遍历,并更新最远出现下标,当到达最后序号时进行一次分割
class Solution {public List<Integer> partitionLabels(String s) {List<Integer> list = new ArrayList<>();int[] record = new int[26];//首先记录字母最后一次出现的下标for(int i=0;i<s.length();i++){record[s.charAt(i)-'a'] = i;}int idx = 0;int last = -1;//然后当遍历下标等于最后一次的下标时,添加字符串长度for(int i=0;i<s.length();i++){idx = Math.max(idx, record[s.charAt(i)-'a']);if(i == idx){list.add(idx-last); //先添加结果到list,再更新last = idx;}}return list;}
}
LeetCode56:合并区间
思路:同样首先按照左边界先排序,然后判断左边界和最右边界
(记得判断=到底属于那种情况)
class Solution {public int[][] merge(int[][] intervals) {List<int[]> res = new LinkedList<>();Arrays.sort(intervals, (x,y)->Integer.compare(x[0],y[0]));int left = intervals[0][0];int right = intervals[0][1];for(int i = 1; i<intervals.length; i++){if(right >= intervals[i][0]){ //重叠,合并right = Math.max(right, intervals[i][1]);}else{ //不重叠,添加旧区间,更新left、rightres.add(new int[]{left, right});left = intervals[i][0];right = intervals[i][1];}}res.add(new int[]{left, right});return res.toArray(new int[res.size()][2]);}
}
其他
LeetCode53:最大子序和
思路:连续子数组局部最优,即遇到连续和count为负数,则立刻放弃当前count,置0,相当于从当前位置重新开始计算连续子数组和。整体最优即用sum来计算循环中count的最大值。
class Solution {public int maxSubArray(int[] nums) {if (nums.length == 1){return nums[0];}int sum = Integer.MIN_VALUE;int count = 0;for (int i = 0; i < nums.length; i++){count += nums[i];sum = Math.max(sum, count); // 取区间累计的最大值(相当于不断确定最大子序终止位置)if (count <= 0){count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和}}return sum;}
}
相关文章:
【Java】HOT100 贪心算法
目录 理论基础 一、简单贪心 LeetCode455:分发饼干 二、中等贪心 2.1 序列问题 LeetCode376:摆动序列 2.2 贪心股票问题 LeetCode121:买卖股票的最佳时机 LeetCode121:买卖股票的最佳时机ii 2.3 两个维度权衡问题 LeetCode135&…...
绝地求生:PUBG杜卡迪联名进入倒计时3天!
大家好,我是闲游盒。 杜卡迪联名已经进入倒计时3天!喜欢的朋友要注意结束时间可千万别错过! 杜卡迪6色车辆 随着五一小长假的结束,本次混沌漫彩通行证也即将结束,本次通行证31级之后没升1级可额外领取1500BP和挑战者纪…...
【论文阅读】Learning Texture Transformer Network for Image Super-Resolution
Learning Texture Transformer Network for Image Super-Resolution 论文地址Abstract1. 简介2.相关工作2.1单图像超分辨率2.2 Reference-based Image Super-Resolution 3. 方法3.1. Texture TransformerLearnable Texture Extractor 可学习的纹理提取器。Relevance Embedding.…...
读字库写FM24C04
/*PCB机板增加读写24C64函数PAST 2017 12 26 08:10 CODE 7382*/ /*按11键进入手动选择,按12键进入参数设定界面 按1存1 2存2 3存3 15存0 16存1236 17读EEPROM显示正确 L1008 13775061792 ******/ #include <reg52.h>…...
boost::asio::ip::tcp::socket set_option
Boost asio 官方教程简介_asio::write-CSDN博客 boost::asio::ip::tcp::socket 是一个用于异步I/O操作的类,它是Boost.Asio库的一部分,专门用于处理TCP套接字。 以下是一个简单的使用 boost::asio::ip::tcp::socket 的例子,这个例子展示了如…...
华为鸿蒙HarmonyOS应用开发者高级认证答案
判断 1只要使用端云一体化的云端资源就需要支付费用(错) 2所有使用Component修饰的自定义组件都支持onPageShow,onBackPress和onPageHide生命周期函数。(错) 3 HarmonyOS应用可以兼容OpenHarmony生态(对…...
ElasticSearch 与 OpenSearch:拉开性能差距
Elasticsearch 与 OpenSearch:扩大性能差距 对于任何依赖快速、准确搜索数据的组织来说,强大、快速且高效的搜索引擎是至关重要的元素。对于开发人员和架构师来说,选择正确的搜索平台可以极大地影响您的组织提供快速且相关结果的能力。在我们…...
Java构造器
构造器 无参构造器有参构造器构造方法VS成员方法总结 概念:也称构造方法、构造函数。作用是构造出来一个类的实例,确保对象得到初始化。 格式: 权限修饰符 类名(无参/有参){ }。 分类: 带参数:有参构造器不带参数&am…...
TiDB系列之:使用TiUP部署TiDB集群最新版本,同时部署TiCDC的详细步骤
TiDB系列之:使用TiUP部署TiDB集群最新版本,同时部署TiCDC的详细步骤 一、部署TiDB集群二、准备环境三、安装 TiUP四、安装TiUP cluster组件五、初始化包含TiCDC的TiDB集群拓扑文件六、检查和修复集群存在的潜在风险七、查看可以安装的tidb版本八、部署 TiDB 集群:九、查看集…...
【经典算法】LeetCode 72. 编辑距离(Java/C/Python3/Go实现含注释说明,中等)
题目描述 给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数。 你可以对一个单词进行如下三种操作: 插入一个字符删除一个字符替换一个字符 原题:LeetCode 72 思路及实现 方式一:动态规划 思路…...
webstorm 常用插件
安装插件步骤: 打开软件,文件 -- 设置-- 插件 -- 输入插件名称 -- 安装 代码截图: code screenShots 先选中代码,按 ctrl shift alt a,就可截取选中的代码颜色注释: comments highlighter 对注释的文字改变颜色高亮成对符号: h…...
clang:在 Win10 上编译 MIDI 音乐程序(二)
先从 Microsoft C Build Tools - Visual Studio 下载 1.73GB 安装 "Microsoft C Build Tools“ 访问 Swift.org - Download Swift 找到 Windows 10:x86_64 下载 swift-5.10-RELEASE-windows10.exe 大约490MB 建议安装在 D:\Swift\ ,安装后大约占…...
【redis】Redis数据类型(三)List类型
目录 List类型介绍特点 List数据结构附:3.2以前的版本(介绍一下压缩列表和双向链表)压缩列表ZipList双向链表LinkedList 常用命令lpush示例 lpushx示例 rpush示例 rpushx示例 LPOP示例 RPOP示例 BLPOP非阻塞行为阻塞行为相同的 key 被多个客户端同时阻塞在 MULTI/EX…...
Java面试题:多线程2
如何停止正在运行的线程 1,使用退出标志,使线程正常退出(run方法中循环对退出标志进行判断) 2,使用stop()方法强行终止(不推荐) 3,调用interrupt()方法中断线程 打断阻塞线程(sleep,wait,join),线程会抛出InterruptedException异常 打断正常的线程,可以根据打断状态来标记…...
T型槽地轨承载力是如何连接整个制造过程的强力桥梁(北重公司设计)
T型槽地轨承载力的定义和计算 T型槽地轨是一种用于工业设备运输和装配的关键组件。它由世界上各行各业的生产商广泛采用,其有效的承载力使其成为连接整个制造过程的强力桥梁。本文将介绍T型槽地轨的承载力以及相关的设计要点和应用。 承载力的定义和计算 承载力是…...
【Numpy】一文向您详细介绍 np.linspace()
【Numpy】一文向您详细介绍 np.linspace() 🌈 欢迎莅临我的个人主页👈 这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的计算机专业人士,热衷于分享技术见…...
VMware虚拟网卡网络适配器出现黄色感叹号
问题发生:VMware在使用Ubuntu的过程中突然卡死,强制关闭开启后就发生了网络无法连接 找到电脑的设备管理发现VMware的适配器出现黄色感叹号 解决方法: 下载软件ccleaner 扫描问题,懒得去找就修复了所有的问题 最后发现适配器…...
论生命价值
我们该如何定义一个人的生命价值,这是一个十分值得我们深思的问题,而谈论到生命的价值,我们先从非人的东西去谈论它的价值,从我们作为人的角度去思考价值,一个东西对我们有用,这个东西能够让我们的主观上的…...
基于Springboot的民航网上订票系统(有报告)。Javaee项目,springboot项目。
演示视频: 基于Springboot的民航网上订票系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…...
ubuntu开启message文件
环境:ubuntu 20.04 1、首先需要修改 /etc/rsyslog.d/50-default.conf 文件;源文件中message被注释,如下图: 2、打开注释: 3、重启服务 systemctl restart rsyslog.service 如此即可!...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
