排序题+贪心

排序力扣题

一:合并区间

56. 合并区间

方法一:先排序再合并

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如图,把区间按照起点从小到达排序,如果起点相同那么按照终点小的优先排序

然后每次记录一个区间,访问下一个区间:

  • 如果下一个区间的起点<=前一个区间的终点,那么把前一个区间终点进行更新,选择两个区间最大的

在这里插入图片描述

  • 如果下一个区间起点>前一个区间终点,说明断开了,把更新后的区间放入结果
 vector<vector<int>> merge(vector<vector<int>>& intervals) {//首先对interval排序sort(intervals.begin(),intervals.end(),\[](vector<int>& a,vector<int>& b){return a[0]<b[0] || (a[0]==b[0]&&a[1]<b[1]);});//初始化区间为-1int left=-1;int right=-1;vector<vector<int>> res;for(auto& val:intervals){int start=val[0];int end=val[1];if(start<=right){//区间起点<=上一个区间终点right=max(right,end);}else{//区间存入结果if(left!=-1){res.push_back({left,right});}//更新区间left=start;right=end;}}//最后一个区间存入结果if(left!=-1){res.push_back({left,right});}return res;}

当然也可以在res无内容或者存放的末尾的终点<当前区间起点时候存结果

    vector<vector<int>> res;for(auto& val:intervals){int start=val[0];int end=val[1];if(res.size()==0 || res.back()[1]<start){res.push_back({start,end});}else{res.back()[1]=max(end,res.back()[1]);}}return res;

方法二:差分

定义一个事件二元组:event

  • 事件的起点:event {区间值,+1}
  • 事件的终点:event{区间值+1,-1}

在这里插入图片描述

所以count从0->正数->0,恰好是求的一个区间

 vector<vector<int>> merge(vector<vector<int>>& intervals) {//定义事件vector<pair<int,int>> event;for(auto& val:intervals){event.push_back({val[0],1});event.push_back({val[1]+1,-1});}//排序sort(event.begin(),event.end());//计数int count=0;int start=-1;vector<vector<int>> ans;for(auto& val:event){if(count==0)//第一个0:记录起点start=val.first;count+=val.second;if(count==0)//又变成0:成为终点ans.push_back({start,val.first-1});}return ans;}

当然也可以直接区间起点+1,区间终点-1,只是需要自定义排序

vector<vector<int>> merge(vector<vector<int>>& intervals) {//定义事件,这里记录:{起点,+1},{终点,-1}vector<pair<int,int>> events;for(auto& val:intervals){events.push_back({val[0],+1});events.push_back({val[1],-1});}//排序sort(events.begin(),events.end(),\[](pair<int,int>& a,pair<int,int>& b){return a.first<b.first ||a.first==b.first && a.second>b.second;});//开始遍历evevtint count=0;int start=-1;vector<vector<int>> ans;for(auto& eve:events){if(count==0){start=eve.first;}count+=eve.second;if(count==0){ans.push_back({start,eve.first});}}return ans;}

自定义函数也可以写成仿函数:

class cmp {public:bool operator()(pair<int, int>& e1, pair<int, int>& e2) {if (e1.first == e2.first)return e1.second > e2.second;return e1.first < e2.first;}// 排序sort(events.begin(), events.end(), cmp());

二:翻转对

493. 翻转对

思路:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​ 递归地对数组进行左右两部分的划分,直至数组长度为1时就结束递归。

这样天然的满足i<j的条件,因为i在左一半数组,j在右一半数组

为了能够使得求逆序对更容易,在合并时候进行排序,然后不断累积求的结果。

遍历一次左一半数组,每次第一个不满足的j值,之前就是符合要求的。

在这里插入图片描述

所以整个过程和分治排序一样,只不过要在合并前统计一次翻转对的个数

统计翻转对的时机:

在得到左右有序序列之后,合并左右有序序列之前。

分治算法的步骤就是:分割+求解+合并

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分治排序过程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解法一:

class Solution {
public:int reversePairs(vector<int>& nums) {mergeSort(nums,0,nums.size()-1);for(auto& val: nums){cout<<val<<" ";}return ans;}
private:int ans=0;void merge(vector<int>& nums,int l,int mid,int r){int i=l;int j=mid+1;int* aux=new int[r-l+1];//[l,r]~[0,r-l]for(int k=0;k<r-l+1;k++){if(i>mid){aux[k]=nums[j++];}else if(j>r){aux[k]=nums[i++];}else if(nums[i]<nums[j]){aux[k]=nums[i++];}else{aux[k]=nums[j++];}}//赋值回numsfor(int i=l;i<=r;i++){nums[i]=aux[i-l];}}void mergeSort(vector<int>& nums,int l,int r){if(l==r) return;int mid=(l+r)>>1;//对半划分mergeSort(nums,l,mid);mergeSort(nums,mid+1,r);//统计翻转对个数int j=mid+1;for(int i=l;i<=mid;i++){while(j<=r && (long)nums[i]>(long)2*nums[j]) j++;//[mid+1,j-1]是符合要求的ans+=j-mid-1;}//合并排序merge(nums,l,mid,r);}
};

把统计个数放在合并还原的函数也可以

   int ans=0;void merge(vector<int>& nums,int l,int mid,int r){int i=l;int j=mid+1;int* aux=new int[r-l+1];//统计翻转对个数for(int i=l;i<=mid;i++){while(j<=r && (long)nums[i]>(long)2*nums[j]) j++;//[mid+1,j-1]是符合要求的ans+=j-mid-1;}//把i,j值还原i=l;j=mid+1;int k=0;//[l,r]~[0,r-l]while(i<=mid && j<=r){if(nums[i]<nums[j]){aux[k++]=nums[i++];}else{aux[k++]=nums[j++];}}while(i<=mid){aux[k++]=nums[i++];}while(j<=r){aux[k++]=nums[j++];}//赋值回numsfor(int i=0;i<r-l+1;i++){nums[i+l]=aux[i];}}void mergeSort(vector<int>& nums,int l,int r){if(l==r) return;int mid=(l+r)>>1;//对半划分mergeSort(nums,l,mid);mergeSort(nums,mid+1,r);//合并排序merge(nums,l,mid,r);}

贪心算法(Greedy Algorithm

对于一道题,要优先考虑分治,搜索,动态规划等基于全局考虑的算法,如果它们时间复杂度比较高,再去考虑能否利用贪心求解。

贪心算法的难点在于:证明这道题可以利用贪心去求解

贪心算法是一种:

  1. 每一步选择当前状态下的最优决策

也就是求:局部最优解

  1. 然后希望每次局部最优的最终结果也是全局最优

通过每次局部最优达到求全局最优的目的

贪心与搜索和动态规划的区别

  1. 贪心不对整个状态空间进行遍历或计算,而是始终按照局部最优选择执行下去,不会回头

因为局部最优并不一定会得到全局最优,所以需要证明:本题每次局部最优可以得到全局最优

  1. 能利用贪心求解的题目也可以利用搜索和动态规划求解,但是贪心一定是最高效的

​ 贪心算法:

  • 不从整体最优上加以考虑,一步一步进行,每一步只以当前情况为基础,根据某个优化测度做出局部最优选择。
  • 省去了为找到最优解要穷举所有可能所必须耗费的大量时间

贪心算法特征

能用贪心算法解决的问题必须满足下面的两个特征:

  • 贪⼼选择性质

一个问题的全局最优解可以通过一系列局部最优解来得到

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 贪心算法在进行选择时,可能会依赖之前做出的选择,但不会依赖任何将来的选择或是子问题的解

  • 贪心算法解决的问题在程序的运行过程中无回溯过程

  • 最优子结构

最优子结构性质:指的是一个问题的最优解包含其子问题的最优解

问题的最优子结构性质是该问题能否用贪心算法求解的关键

在这里插入图片描述

​ 如果原问题 𝑆 的最优解=「第 𝑎1 步通过贪心选择的局部最优解」+「 子问题𝑆子问题 的最优解」.则说明该问题满足最优子结构性质。

  • 如果不能利用子问题的最优解推导出整个问题的最优解,那么这种问题就不具有最优子结构

力扣题—贪心

一:分饼干

455. 分发饼干

解法一:大饼干分给大孩子

把孩子和饼干按照升序排序,然后遍历孩子,如果孩子胃口值<=当前大饼干,就把饼干分配给他

不然的话,:也就是饼干小于胃口,放弃当前孩子,寻找下一个更小的孩子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

 int findContentChildren(vector<int>& g, vector<int>& s) {//每个孩子i有胃口值g[i]//每个饼干j有尺寸值s[j]//目标:尽可能的满足孩子多int j=0;int col=0;//降序排序sort(g.begin(),g.end(),greater<int>());sort(s.begin(),s.end(),greater<int>());//遍历胃口,优先把大饼干给大胃口for(int i=0;i<g.size() && j<s.size();i++){if(g[i]<=s[j]){//分配饼干col++;j++;}}return col;}

循环条件还可以:

  • for(int i=0;i<g.size();i++){if(j<s.size() && s[j]>=g[i]){//饼干可以分给当前孩子col++;j++;}}
    
  • for(int i=0;i<g.size();i++){if(j==s.size()) break;if(s[j]>=g[i]){//饼干可以分给当前孩子col++;j++;}}
    
  • int i=0,j=0;int col=0;//遍历孩子分饼干while(i<g.size() && j<s.size()){if(s[j]>=g[i]){i++;j++;col++;}else{//放弃孩子i++;}}
    

方法二:小饼干分给小孩子

这种情况是,遍历到下一个孩子之前,需要不断放弃尺寸小饼干,直至找到满足当前孩子胃口饼干后,接着遍历

在这里插入图片描述

int findContentChildren(vector<int>& g, vector<int>& s) {//每一个孩子i有胃口g[i]//每一块饼干j有尺寸s[j]/*孩子和饼干升序排序*/sort(g.begin(),g.end());sort(s.begin(),s.end());//遍历孩子int j=0;int col=0;for(int i=0;i<g.size();i++){//遍历饼干,找到一个最小的满足胃口while(j<s.size() && s[j]<g[i]) j++;if(j<s.size()){//找到了j++;col++;}}return col;}

总结:

小饼干分给小孩子,相当于放弃饼干

因为最小饼干不能给小孩子,一定也不能给其他孩子

大饼干分给大孩子,相当于放弃孩子

因为大饼干肯定会被孩子吃,所以优先满足大胃口

二:买卖股票

122. 买卖股票的最佳时机 II

这里同一天既可以买股票,也可以卖股票,还可以买卖同时进行

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如图:后一天比前一天大就累计利润,相当于前一天买后一天卖;后一天比前一天小就跳过

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

三:跳跃游戏

45. 跳跃游戏 II

分析:假设当前位置为index,而且该位置可以跳的最大距离为:nums[index]

​ 则:枚举1~nums[index]的所有可能,然后选择到达位置后,下一个位置的最远距离

也就是说:如果到达的位置能达到的下一个位置最远,就选该位置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

 int jump(vector<int>& nums) {int n=nums.size();int curPos=0;int step=0;//跳跃次数while(curPos < n-1){//不到达最后位置// 当前位置的跳跃步数为0,到达不了if(nums[curPos]==0) return -1;//枚举位置终点int right=curPos+nums[curPos];//如果直接能超过终点,直接returnif(right>=n-1) return step+1;int nextPos=curPos+1;for(int i=curpos+2;i<=right;i++){if(i+nums[i]>nextPos+nums[nextPos])nextPos=i;}//选择该位置,步数+1curPos=nextPos;step++;}return step;}

方法二:

将start和end初始化在第一个位置,然后计算可到达的最远距离maxPos

每次:start等于上一个end+1,end选择maxPos,其实这就是遍历每一个位置取最大

在这里插入图片描述

int jump(vector<int>& nums) {//start和end初始化第一个位置int start=0,end=0;int ans=0;//返回结果while(end < nums.size()-1){int maxPos=0;for(int i=start;i<=end;i++){maxPos=max(maxPos,i+nums[i]);}//更新位置start=end+1;end=maxPos;ans++;//跳了一次}return ans;}

上述代码可以优化

  • 可以在i==end统计次数
for (int i = start; i < nums.size() - 1; i++) {maxPos = max(maxPos, i + nums[i]);//因为i从头遍历到最后,所以==end时候,步数+1if (i == end) {start = end + 1;end = maxPos;ans++;}}
  • 可以没有起点

区间遍历[start,end],start每次更细为end+1,所以相当于从0依次遍历

 for (int i = 0; i < nums.size() - 1; i++) {maxPos = max(maxPos, i + nums[i]);//因为i从头遍历到最后,所以==end时候,步数+1if (i == end) {end = maxPos;ans++;}}https://leetcode.cn/problems/minimum-initial-energy-to-finish-tasks/)

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

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

相关文章

Hexo+Github搭建个人博客教程

hexo官网&#xff1a;https://hexo.io/zh-cn/ butterfly 主题设置&#xff1a;https://butterfly.js.org/ GitHub地址&#xff1a;https://github.com/jerryc127/hexo-theme-butterfly 基础命令 初始化博客命令&#xff1a;hexo init “文件名” 开启本地服务&#xff08;本…

支付交易——在线支付系统基本概念

摘要 本文聚集于实战&#xff0c;只讲解最实用的知识点&#xff0c;至于支付起源、在线支付发展历程等科普知识&#xff0c;感兴趣的读者可参考其它优秀的支付类书籍或网络上其它优秀的文章。本章内容对大部分专业概念进行了极致简化&#xff0c;以便更好地帮助读者入门。实际…

XSS(跨站脚本攻击)

1.什么是xss XSS全称&#xff08;Cross Site Scripting&#xff09;跨站脚本攻击&#xff0c;为了避免和CSS层叠样式表名称冲突&#xff0c;所以改为了 XSS&#xff0c;是最常见的Web应用程序安全漏洞之一,XSS是指攻击者在网页中嵌入客户端脚本&#xff0c;通常是JavaScript编写…

Word中插入Mathtype右编号,调整公式与编号的位置

当你已经将mathtype内置于word后&#xff0c;可以使用右编号快速插入公式 但是往往会出现公式和编号出现的位置或之间的距离不合适 比如我在双栏下插入公式&#xff0c;会发现插入的公式与编号是适用于单栏的 解决办法&#xff1a; 开始->样式->MTDisplayLquation -&g…

【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义

目录 问题解决方案讨论 问题 本文讨论一些按照特定的文本模式进行的查找和匹配。 解决方案 如果想要匹配的只是简单文字&#xff0c;通常我们使用一些内置的基本字符串方法即可&#xff0c;如&#xff1a;str.find()&#xff0c;str.startwith()&#xff0c;str.endswith() …

电脑存储设备,固态硬盘介绍,usb接口

简介 存储设备分为两大类主存和辅存&#xff0c;另外还有专门提供存储服务的网络存储 主存储器 随机存取存储器&#xff08;RAM, Random Access Memory&#xff09; 特点&#xff1a;高速、易失性存储器&#xff0c;断电后数据丢失。用途&#xff1a;临时存储正在使用的数据…

【Oracle生产运维】数据库服务器负载过高异常排查处理

说明 在Oracle数据库运维工作中&#xff0c;经常会遇到Oracle数据库服务器平均负载&#xff08;load average&#xff09;突然异常升高&#xff0c;如果放任不管&#xff0c;严重的情况下会出现数据库宕机、服务器重启等重大故障。因此&#xff0c;当发现数据库服务器平均负载…

log4j日志打印导致OOM问题

一、背景 某天压测&#xff0c;QPS压到一定值后机器就开始重启&#xff0c;出现OOM&#xff0c;好在线上机器配置了启动参数-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/**/**heapdump.hprof。将dump文件下载到本地&#xff0c;打开Java sdk bin目录下的jvisualvm工具&a…

事业单位——被逆袭篇

目录 一、结果 二、考试 三、时间 四、复习 五、总结 一、结果 图1&#xff1a;2024年浙江广播电视集团下属浙江省中波发射管理中心公开招聘笔面试结果 准考证号笔试面试总成绩排名备注107016070.866.48310702416555.44107134390.871.681入围107146869.869.08210715406454.…

电影推荐系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;免费电影管理&#xff0c;付费电影管理&#xff0c;电影论坛管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;付费电影&#x…

Java:111-SpringMVC的底层原理(中篇)

这里续写上一章博客&#xff08;110章博客&#xff09;&#xff1a; 现在我们来学习一下高级的技术&#xff0c;前面的mvc知识&#xff0c;我们基本可以在67章博客及其后面相关的博客可以学习到&#xff0c;现在开始学习精髓&#xff1a; Spring MVC 高级技术&#xff1a; …

Spring Boot 项目启动时在 prepareContext 阶段做了哪些事?

概览 如果你对Spring Boot 启动流程还不甚了解&#xff0c;可阅读《Spring Boot 启动流程详解》这篇文章。如果你已了解&#xff0c;那就让我们直接看看prepareContext() 源码。 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironme…

邻接矩阵深度优先遍历

深度优先遍历&#xff0c;就是一条路&#xff0c;走到底&#xff0c;然后再走下一个岔路。 下面代码就主要使用递归来进行&#xff0c;当然也可以借助栈来实现。 private void traverse(char v, boolean[] visited) {int index _getIndexOfV(v);//获取v顶点在vertexS字符数组…

synchronized 的底层实现

用户态与内核态 JDK 早期&#xff0c;synchronized 叫做重量级锁&#xff0c; 因为申请锁资源必须通过 kernel&#xff08;指大多数操作系统的核心部分&#xff09;&#xff0c;系统调用。 ;hello.asm ;write(int fd, const void *buffer, size_t nbytes)section datamsg db …

Spring Boot整合Redis实现发布/订阅功能

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

selenium非全新的方式同时启动多个浏览器又互不影响的一种实现方法,欢迎讨论!

最近在做模拟浏览器批量定时自动点击实现批量操作功能&#xff0c;主要使用selenium&#xff0c;但是发现selenium直接调用本地浏览器&#xff0c;启动的是一个全新的&#xff08;与手动打开的不一致&#xff09;&#xff0c;网站可以检测到&#xff0c;每次都要双重验证(密码登…

AI服务器相关知识

在当今社会&#xff0c;人工智能的应用场景愈发广泛&#xff0c;如小爱同学、天猫精灵等 AI 服务已深入人们的生活。随着人工智能时代的来临&#xff0c;AI 服务器也开始在社会各行业发挥重要作用。那么&#xff0c;AI 服务器与传统服务器相比&#xff0c;究竟有何独特之处&…

收音机的原理笔记

1. 收音机原理 有线广播&#xff1a;我们听到的声音是通过空气振动进行传播&#xff0c;因此可以通过麦克风&#xff08;话筒&#xff09;将这种机械振动转换为电信号&#xff0c;传到远处&#xff0c;再重新通过扬声器&#xff08;喇叭&#xff09;转换为机械振动&#xff0c…

物联网概念

物联网 物联网简介物联网体系结构物联网体系结构定义物联网体系结构设计原则物联网体系结构四层物联网体系结构感知控制层数据传输层数据处理层应用决策层 物联网关键技术感知标识技术网络与通信技术云计算技术安全技术 已有物联网相关应用架构无线传感器网络的体系结构EPC/UID…

DeepSORT(目标跟踪算法)中自由度决定卡方分布的形状

DeepSORT&#xff08;目标跟踪算法&#xff09;中自由度决定卡方分布的形状 flyfish 重要的两个点 自由度决定卡方分布的形状&#xff08;本文&#xff09; 马氏距离的平方在多维正态分布下服从自由度为 k 的卡方分布 独立的信息 在统计学中&#xff0c;独立的信息是指数据…