排序题+贪心

排序力扣题

一:合并区间

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.mzph.cn/web/25511.shtml

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

相关文章

Vue TypeScript 实战:掌握静态类型编程

title: Vue TypeScript 实战&#xff1a;掌握静态类型编程 date: 2024/6/10 updated: 2024/6/10 excerpt: 这篇文章介绍了如何在TypeScript环境下为Vue.js应用搭建项目结构&#xff0c;包括初始化配置、创建Vue组件、实现状态管理利用Vuex、配置路由以及性能优化的方法&#x…

数据中心网络运维探讨

数据中心网络运维探讨 数据中心网络运维通过科学的网络架构设计、实时监控管理、智能化运维工具和全面的安全防护&#xff0c;确保网络的高效、安全运行。它不仅提升了运维效率和网络可靠性&#xff0c;还保障了业务的连续性和数据安全。随着技术的不断进步&#xff0c;智能化…

推测性解码:加速多模态大型语言模型的推理

大模型&#xff08;LLMs&#xff09;以其卓越的性能在多个应用场景中大放异彩。然而&#xff0c;随着应用的深入&#xff0c;这些模型的推理速度问题逐渐凸显。为了解决这一挑战&#xff0c;推测性解码&#xff08;Speculative Decoding, SPD&#xff09;技术应运而生。本文深入…

Vue 2看这篇就够了

Vue 2 技术文档 Vue.js 是一款用于构建用户界面的渐进式框架。与其他重量级框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。而 Vue.js 2&#xff08;以下简称 Vue…

Vue2基础:.sync修饰符的使用,认识,作用,本质案例演示,实现父子之间的通信。

.sync的作用&#xff1a; 可以实现子组件与父组件数据的双向绑定&#xff0c;简化代码。 与v-model的不同点,prop属性名可以自定义&#xff0c;不要一定要用value. .sync的本质&#xff1a; 就是&#xff1a;属性名和update&#xff1a;属性名合写。 下面我们进行代码演示…

探索智慧景区票务系统的架构与应用

随着旅游业的迅速发展&#xff0c;智慧景区票务系统已经成为提升景区管理效率、优化游客体验的重要工具。智慧景区票务系统的架构设计与应用&#xff0c;将现代信息技术与景区管理相结合&#xff0c;为景区的门票销售、入园管理和游客服务提供了全新的解决方案。本文将深入探讨…

【西瓜书】9.聚类

聚类任务是无监督学习的一种用于分类等其他任务的前驱过程&#xff0c;作为数据清洗&#xff0c;基于聚类结果训练分类模型 1.聚类性能度量&#xff08;有效性指标&#xff09; 分类任务的性能度量有错误率、精度、准确率P、召回率R、F1度量(P-R的调和平均)、TPR、FPR、AUC回归…

滑动窗口算法:巧妙玩转数据的窗外世界

✨✨✨学习的道路很枯燥&#xff0c;希望我们能并肩走下来! 文章目录 目录 文章目录 前言 一 滑动窗口是什么&#xff1f; 二 相关题目解析 1. 长度最小的子数组 &#x1f973;题目解析 &#x1f973;算法原理 ✏️思路1 暴力枚举出所有子数组之和 ✏️思路2 滑动窗…

LangChain开发【NL2SQL】应用

前言 关于LangGraph的简单介绍&#xff0c;请参考这篇博客&#xff1a; LangGraph开发Agent智能体应用【基础聊天机器人】-CSDN博客 对比LangChain实现NL2SQL 关于用LangChain开发NL2SQL的Agent应用&#xff0c;在这篇博客提供了完整的代码实现&#xff1a; LangChain开发…

AI网络爬虫:批量爬取豆瓣图书搜索结果

工作任务&#xff1a;爬取豆瓣图书搜索结果页面的全部图书信息 在ChatGPT中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个爬虫Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 用 fake-useragent库设置随机的请求头&#xff1b; 设置chr…

NFT 智能合约实战-快速开始(1)NFT发展历史 | NFT合约标准(ERC-721、ERC-1155和ERC-998)介绍

文章目录 NFT 智能合约实战-快速开始(1)NFT发展历史国内NFT市场国内NFT合规性如何获得NFT?如何查询NFT信息?在 OpenSea 上查看我们的 NFT什么是ERC721NFT合约标准ERC-721、ERC-1155和ERC-998 对比ERC721IERC721.sol 接口内容关于合约需要接收 ERC721 资产 onERC721Received…

【教学类-64-02】20240610色块眼力挑战(二)-2-25宫格色差10-100(10倍)(星火讯飞)

背景需求 以下的色块眼里挑战需要人工筛选图片&#xff0c;非常繁琐。 【教学类-64-01】20240607色块眼力挑战&#xff08;一&#xff09;-0-255随机底色-CSDN博客文章浏览阅读446次&#xff0c;点赞12次&#xff0c;收藏5次。【教学类-64-01】20240607色块眼力挑战&#xff…

Linux安装Docker | 使用国内镜像

环境 CentOS7 先确认能够上网 curl www.baidu.com返回该输出说明网络OK 步骤一&#xff1a;安装gcc 和 gcc-c yum -y install gccyum -y install gcc-c步骤二&#xff1a;安装Docker仓库 yum install -y yum-utils接下来配置yum的国内镜像 yum-config-manager --add-re…

tomcat服务器之maxHttpHeaderSize

背景&#xff1a;在OA流程表单中&#xff0c;填写了200条数据&#xff0c;一提交&#xff0c;秒报400错误&#xff0c;且请求没有打到后端中&#xff08;无报错日志&#xff09;&#xff0c;一开始以为是谷歌浏览器的问题&#xff0c;可百度上关于这个错误的解决方案都是清除缓…

转让北京劳务分包地基基础施工资质条件和流程

地基基础资质转让流程是怎样的?对于企业来说&#xff0c;资质证书不仅是实力的证明&#xff0c;更是获得工程承包的前提。而在有了资质证书后&#xff0c;企业才可以安心的准备工程投标&#xff0c;进而在工程竣工后获得收益。而对于从事地基基础工程施工的企业&#xff0c;需…

特种设备起重机指挥题库附答案

1、【多选题】力的三要素是指:( )。(ACD) A、力的大小 B、力的单位 C、力的方向 D、力的作用点 2、【多选题】司索作业规范正确的要求是( )(ABC) A、吊点正确 B、吊索挂设合理 C、绑扎牢靠 D、吊索长短一致 3、【多选题】圆柱形物体兜吊时&#xff0c;一定要放空圈&#…

【python】python GUI编程--tkinter模块初探

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Keil软件仿真的使用

一、软件的初始化设置 初始设置可以按照下图&#xff0c;这里我使用的是STM32F103C8T6&#xff0c;所以单片机型号为STM32F103C8&#xff0c;这个设置在Debug目录下。然后进行时钟的设置&#xff0c;我们板上晶振为8M&#xff0c;这里将时钟改为8. 或许有人想问如果是别的型号单…

Effective Java 1 用静态工厂方法代替构造器

知识点上本书需要会Java语法和lang、util、io库&#xff0c;涉及concurrent和function包。 内容上主要和设计模式相关&#xff0c;代码风格力求清晰简洁&#xff0c;代码尽量复用&#xff0c;组件尽量少依赖&#xff0c;错误尽早发现。 第1个经验法则&#xff1a;用静态工厂方…

Chroium 源码目录结构分析(1):源码目录体积一栏

获取源码 首先&#xff0c;我们拉一份最新的源代码&#xff08;笔者是2024.6.6日拉取的&#xff09;&#xff1a; fetch --nohistory chromium 源码预处理 如果运行build&#xff0c;会生成许多生成的代码&#xff0c;因此我们不运行build。 然后&#xff0c;把干扰后续分析…