2.贪心算法.基础

2.贪心算法.基础

  • 基础知识
  • 题目
    • 1.分发饼干
    • 2.摆动序列
      • 2.1.思路二:动态规划法
    • 3.最大子序和
    • 4.买股票的最佳时机2
      • 4.1.思路二:动态规划法
      • 4.2.买股票的最佳时机
    • 5.跳跃游戏
      • 5.1.跳跃游戏2
    • 6.K次取反后最大化的数组和
    • 7.加油站
    • 8.分发糖果
  • 总结

基础知识

什么是贪心? 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。
贪心的套路
贪心算法并没有固定的套路。不好意思,也没有! 靠自己手动模拟,如果模拟可行,就可以试一试贪心策略,如果不可行,可能需要动态规划。那如何验证可不可用贪心算法?最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧
一般的数学证明有如下两种方法:
1.数学归纳法
2.反证法

面试中基本不会让面试者现场证明贪心的合理性,代码写出来跑过测试用例即可,或者自己能自圆其说理由就行了。
贪心一般解题步骤,一般分为如下四步:
1.将问题分解为若干个子问题
2.找出适合的贪心策略
3.求解每一个子问题的最优解
4.将局部最优解堆成全局最优解
做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。

贪心没有套路,说白了就是常识性推导加上举反例。贪心的一般解题步骤,大家可以发现这个解题步骤也是比较抽象的,不像是二叉树,回溯算法,给出了那么具体的解题套路和模板。

题目

1.分发饼干

(题目链接)
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
在这里插入图片描述
为了不浪费饼干的尺寸,打算尽量用尺寸最大的饼去给胃口最大的孩子,以此往下推,每一步充分发挥这个当前饼尺寸的作用。

    int findContentChildren(vector<int>& g, vector<int>& s) {std::sort(g.begin(), g.end());std::sort(s.begin(), s.end());int index=0; // for personfor(int i=0; i<s.size(); i++){ // for cakeif(index<g.size() && g[index]<=s[i]) index++;}return index;}

for循环可以从饼开始匹配,从人开始匹配,但要主要方向的不同


2.摆动序列

(题目链接)
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。例如, [1,7,4,9,2,5] 是一个摆动序列,而[1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列。
因此题目要求是 给定一个整数序列,返回作为摆动序列的最长子序列的长度
这是思路是:局部最优——除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值;整体最优——整个序列有最多的局部峰值,从而达到最长摆动序列。
实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)
在这里插入图片描述
要处理一下三种特殊情况,结合题目要求情况一的结果应该是3;情况二的结果应该是2;情况三的结果应该是2,因为单调种的平坡不能算是峰值。那如何如何消除这些平坡的影响呢?因为摆动是通过prediffcurdiff的符号变化来添加峰值计数,我们只要让prediff在发生摆动时,才修改就行了,对于平坡的情况,pre的符号就维持不变。

    int wiggleMaxLength(vector<int>& nums) {if(nums.size()<=1) return nums.size();int curdiff = 0;int prediff = 0;int res = 1;for(int i=0; i<nums.size()-1; i++){curdiff = nums[i+1]-nums[i];if((prediff<=0 && curdiff>0) || (prediff>=0 && curdiff<0)){res++;prediff = curdiff;}}return res;}

时间复杂度:O(n^2);空间复杂度:O(n)

2.1.思路二:动态规划法


3.最大子序和

(题目链接)
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和
暴力解法:通过两层for循环,完成整数数组的子集和的统计,最后比较得出最大的值即可。
其时间复杂度:O(n^2);空间复杂度:O(1)

贪心解法:局部最优——最大连续和的,设置另外一个数组存放原本数组上从0开始连续和>0的数值,当连续和<0时,则从下一个数值开始计数。最后得到这个连续
在这里插入图片描述

    int maxSubArray(vector<int>& nums) {int res = INT_MIN;int count = 0;for(int i=0; i<nums.size(); i++){count += nums[i];if(count>res) res = count;if(count<0) count=0;}return res;}

这里res初始化为INT_MIN是为了处理当数组首个字母是负数的情况;


4.买股票的最佳时机2

(题目链接)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格:计算你所能获取的最大利润(但注意你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票))。
例如:输入: [7,1,5,3,6,4]:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

思路:1.想要获取利润,至少两天为一个交易单元 2.初始想法是选择一个低价买入,再高价卖出…一直这样循环 3.

    int maxProfit(vector<int>& prices) {int res = 0;for(int i=1; i<prices.size(); i++){res += max(prices[i]-prices[i-1], 0);}return res;} 

4.1.思路二:动态规划法

4.2.买股票的最佳时机

(题目链接)
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。只有一个购买-卖出的周期,也就是一次获取利润的机会。

    int maxProfit(vector<int>& prices) {int res = 0;int min_pri = INT_MAX;for(int i=0; i<prices.size(); i++){min_pri = prices[i]<min_pri? prices[i]:min_pri;res = res<prices[i]-min_pri? prices[i]-min_pri: res;}return res;}

5.跳跃游戏

(题目链接)
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false

    bool canJump(vector<int>& nums) {int cover = 0;if(nums.size()==1) return true;for(int i=0; i<=cover; i++){cover = max(i+nums[i], cover);if(cover >= nums.size()-1) return true;}return false;}

5.1.跳跃游戏2

(题目链接)
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:目标是使用最少的跳跃次数,并返回该次数。
在这里插入图片描述
与上一题不同,该题要求最小步数,因此需要设置两个变量存储当前步可覆盖范围,下一步可覆盖范围:循环特点是 没进入一层cover时,会更新precover值,并与之前的precover比较覆盖;当cover=curcover时,步数统计count+1,且将precover值赋给curcover;最后当precover覆盖数组末尾时退出。

    int jump(vector<int>& nums) {if(nums.size()==1) return 0;// 两者初始化从0出发int curcover = 0;int precovner = 0;int count = 0;for(int i=0; i<nums.size(); i++){//实时计算在下一步可到达的范围precovner = max(i + nums[i], precovner);if(i==curcover){count++;curcover = precovner; //转化为当前步可到达的范围if(precovner>=nums.size()-1) break;}}return count;

6.K次取反后最大化的数组和

(题目链接)
给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。重复这个过程恰好 k 次。可以多次选择同一个下标 i 。以这种方式修改数组后,返回数组 可能的最大和 。
基本思路是1.将数组中的负数尽量反转为正数 2.若剩余数组均为正数,此时所剩k值若为奇数,则选择一个值最小的正数反转为负数, 若剩余k值是偶数,则无影响。

	// 加了绝对值排序法int largestSumAfterKNegations(vector<int>& nums, int k) {std::sort(nums.begin(), nums.end(), cmp);for(int i=0; i<nums.size(); i++){if(nums[i]<0 && k>0){nums[i] *= -1;k--;}}if(k%2 == 1) nums[nums.size()-1] *= -1;int res = 0;for(int n:nums) res += n;return res;}//正常递增序列排序法int largestSumAfterKNegations(vector<int>& nums, int k) {std::sort(nums.begin(), nums.end());int min_abs = 0;for(int i=0; i<nums.size(); i++){if(nums[i]<0 && k>0){nums[i] *= -1;k--;}min_abs = abs(nums[min_abs])<abs(nums[i])? min_abs: i;}if(k%2==1) nums[min_abs] *= -1;int res=0;for(int n:nums) res += n;return res;}

7.加油站

(题目链接)
在这里插入图片描述
暴力的方法很明显就是O(n^2)的,遍历每一个加油站为起点的情况,模拟一圈。

贪心算法1:情况一若gas总和小于cost总和,则一定跑不完一圈;情况二,从0开始出发,累计一圈下来,若中途累加值<0,则说明从0出发不可行;情况三,此时京start后移,即start从尾部朝头部移动,若该节点和能使之前中途累加值的负值填平,则可以从该节点出发。
贪心算法2:当局部连续数组和<0时,说明在i步遇到较大的负值,到时总和不满足,此时可以判断从i之前开始一定不可行(理解这个判断:说明从start到i-1步及之前是满足>0约束的,若存在start~i之间的一个值index到i值的区间满足>0,则说明在start到index区间的值<0,这不符合假设。),至少从i+1开始。

	// 贪心1:最少满足start延后int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int cursum = 0;int min = INT_MAX;for(int i=0; i<gas.size(); i++){int res = gas[i]-cost[i];cursum += res;if(cursum<min){min = cursum;}}if(cursum<0) return -1;if(min>=0) return 0;for(int i=gas.size()-1; i>0; i--){int res = gas[i]-cost[i];min += res;if(min>=0) return i;}return -1;}// 贪心2:最长局部累加和int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int cursum = 0;int totalsum = 0;int start = 0;for(int i=0; i<gas.size(); i++){cursum += gas[i] - cost[i];totalsum += gas[i] - cost[i];if(cursum<0){start = i+1;cursum = 0;}}if (totalsum<0) return -1;return start;}

时间复杂度:O(n);空间复杂度:O(1)


8.分发糖果

(题目链接)
这道题目有点意思 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。你需要按照以下要求,给这些孩子分发糖果:
1.每个孩子至少分配到 1 个糖果。 2.相邻两个孩子评分更高的孩子会获得更多的糖果。请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目
确定左孩子比右孩子大的情况一定是从后面往前遍历,否则不能利用右边孩子的candy的比较情况,得到vec1;确定右孩子比左孩子大的情况是从前往后遍历,这样也是未来利用左孩子的candy的比较情况,得到vec2;最后取candy的vector时,取vec1,vec2各个索引位置上candy的max情况——这样即满足了右孩子比左孩子大,左孩子比右孩子大的情况。

    int candy(vector<int>& ratings) {std::vector<int> candyvec(ratings.size(), 1);for(int i=1; i<ratings.size(); i++){if(ratings[i]>ratings[i-1]) candyvec[i] = candyvec[i-1]+1;}for(int i=ratings.size()-2; i>=0; i--){if(ratings[i]>ratings[i+1]) candyvec[i] = max(candyvec[i+1]+1, candyvec[i]);}int res = 0;for(int n:candyvec) res += n;return res;}

总结

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

(三)前端javascript中的数据结构之链表上

在js中&#xff0c;没有为我们提供原生的数据结构支持的&#xff0c;但是在java中是有提供的。所以需要我们去模拟这种结构实现。 链表中最关键的一个元素&#xff0c;就是头节点&#xff0c;头节点不存储数据&#xff0c;指向第一个节点链表中几乎所有的操作都要从头结点开始。…

安全防御(防火墙)

第二天&#xff1a; 1.恶意程序---一般会具有一下多个或则全部特点 1.非法性&#xff1a;你未经授权它自动运行或者自动下载的&#xff0c;这都属于非法的。那恶意程序一般它会具有这种特点&#xff0c; 2.隐蔽性&#xff1a;一般隐藏的会比较深&#xff0c;目的就是为了防止…

Proxifier代理的其他妙用方法(内网渗透、反溯源、小程序公众号)

目录 配置说明 1. 通过Proxifier进行内网渗透 2. 通过Proxifier将VM虚拟机代理 3. 通过Proxifier进行小程序抓包 4. 补充 文章截取处 配置说明 配置其他的之前,要新增一个代理规则,如下: 127.0.0.1; ::1 让它 Direct (直接连接,即不走任何代理)即可 说明: ::1是I…

下一代 CSS 框架:Mojo CSS

前言 Tailwind CSS 推出即受到广大开发者的欢迎&#xff0c;当前 Github star 数已达 77.8k。它是一个功能类优先&#xff08;utility-first&#xff09;的 CSS 框架&#xff0c;它提供了一系列功能类&#xff0c;让开发者可以在 HTML 中通过组合这些功能类&#xff08;原子类…

EPICS数据库示例

本文目标是使用EPICS数据库示例帮助新手理解如何使用不同的示例。 1、使用seq和mbbo的简单选择器 这个简单示例展示了如何使用一个mbbo和一个seq来旋转哪个值将被设置到一个PV。 # 这个mbbo记录将选择将运行seq的哪段 record(mbbo, "CHOOSE") {field(VAL, "…

c#字符串常用方法

目录 1.字符串的处理常用方法 1.1 Format 1.2 IsNullOrEmpty和IsNullOrWhiteSpace 1.3 Equals 1.4 Contains 1.5 Length 1.6 Substring 1.7 IndexOf和LastIndexOf 1.8 ​​​​​​​StartsWith 和 EndsWith 1.9 ​​​​​​​Remove 1.10 ​​​​​​​Revserse…

基于Java+SpringMvc+Vue技术的实验室管理系统设计与实现

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

如何手工DIV一个小车:基于树莓派和总线舵机的智能小车实现

成品演示&#xff1a;bilibili - 悄悄的魔法书 代码仓库&#xff1a;github - flying forever 或者 gitee - 清风莫追 文章目录 1 引言1.1 课题背景1.2 课题意义1.3 课题目的 2 课题相关知识与开发环境3 课题的总体设计4 课题的详细设计与实现4.1 小车物理结构4.1.1 轮子4.1.2 …

2024年最新ComfyUI汉化及manager插件安装详解!

前言 在ComfyUI文生图详解中&#xff0c;学习过如果想要安装相应的模型&#xff0c;需要到模型资源网站&#xff08;抱抱脸、C站、魔塔、哩布等&#xff09;下载想要的模型&#xff0c;手动安装到ComfyUI安装目录下对应的目录中。 为了简化这个流程&#xff0c;我们需要安装Co…

如何在 PostgreSQL 中实现数据的去重操作,尤其是对于复杂的数据结构?

文章目录 一、基本数据类型的去重二、多列数据的去重三、复杂数据结构的去重&#xff08;一&#xff09;数组类型的去重&#xff08;二&#xff09;JSON 类型的去重&#xff08;三&#xff09;结构体类型&#xff08;复合类型&#xff09;的去重 四、使用 GROUP BY 进行去重五、…

数据结构--堆,堆排序

1.树概念及结构 1.1树的概念 树是一种 非线性 的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 。 有一个 特殊的结…

自动高速开箱机:如何助力电商物流行业

在电商飞速发展的今天&#xff0c;物流行业也迎来了前所未有的挑战与机遇。为了满足消费者对快速、高效、安全的配送需求&#xff0c;各大电商平台和物流公司纷纷寻求技术革新&#xff0c;其中&#xff0c;自动高速开箱机凭借其独特的优势&#xff0c;在电商物流中崭露头角&…

vulnhub-Os-hackNos-3(包含多种靶机获取不了IP地址情况)

下载靶机 通过VMware搭建 网络问题是个关键点 我们点击开启虚拟机&#xff0c;到开机的页面我们回车选择第二个Ubuntu的高级选项 (如果出不来这个选择界面&#xff0c;开机时按下shift键) 进到高级选项&#xff0c;我们再次回车选择第二个进入Linux内核版本的恢复模式 回车后…

BaseServlet的封装

创建BaseServlet的必要性 如果不创建BaseServlet&#xff0c;现在我们只要实现一个功能&#xff0c;我们就需要创建一个servlet! 例如:用户模块(登录&#xff0c;注册&#xff0c;退出录&#xff0c;激活&#xff0c;发送邮件等等功能) 也就是说&#xff0c;我们必须要创建一…

Vue3使用ref绑定组件获取valueRef.value为null的解决

问题&#xff1a; onMounted(() > {nextTick(()>{console.log(treeselectRef, treeselectRef.value);console.log(treeselectRef.value, treeselectRef.value);}); });输出&#xff1a; 查看绑定和定义都没有问题&#xff0c;还是获取不到 解决&#xff1a;使用getCur…

YOLOv5+DecoupleHead解耦头(YOLOx)

一、解耦头原理 在目标检测中,分类任务和回归任务之间的冲突是一个众所周知的问题。因此,用于分类和定位的解耦头被广泛应用于大多数一级和二级探测器。但是,由于YOLO系列的主干和特征金字塔(如FPN, PAN)不断演化,它们的检测头仍然是耦合的。 从下表可以看出,头耦合时端…

leetcode 1398 购买了产品A和产品B却没有购买产品C的顾客(postgresql)

需求 Customers 表&#xff1a; ---------------------------- | Column Name | Type | ---------------------------- | customer_id | int | | customer_name | varchar | ---------------------------- customer_id 是这张表的主键。 customer_name 是顾客的名称。 Order…

水果商城系统 SpringBoot+Vue

1、技术栈 技术栈&#xff1a;SpringBootVueMybatis等使用环境&#xff1a;Windows10 谷歌浏览器开发环境&#xff1a;jdk1.8 Maven mysql Idea 数据库仅供学习参考 【已经答辩过的毕业设计】 项目源码地址 2、功能划分 3、效果演示

【软件分享】我们为分类而生—eCognition

分类是各位小伙伴入门遥感需要做的一项基础的工作&#xff0c;在进行遥感影像中的地物进行分类和提取时&#xff0c;如何提高分类精度&#xff0c;常常令人头疼。今天小编带来此前接触过的一个工具&#xff0c;他的名字是—eCognition&#xff0c;感觉比ENVI好用&#xff0c;在…

gui创新点charts图表

import javax.swing.*; import java.awt.*;public class ComboChartExample extends JPanel {Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);// 数据int[] values {100, 200, 150, 300, 250};int[] lineValues {120, 180, 160, 280, 230};Str…