【基础算法总结】分治—快排
分治—快排
- 1.分治
- 2.颜色分类
- 3.排序数组
- 4.数组中的第K个最大元素
- 5.库存管理 III
点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃
1.分治
分治思想就如同它的名字一样:分而治之。
将一个大问题划分成若干个相同或者相识的子问题。然后在将子问题在划分成若干个相同或者相识的子问题,直到划分到不能在划分。然后解决子问题,子问题都解决完了,大问题也就被解决完了。快速排序和归并排序就用的分治思想。
以前我们学快速排序是在数组中选择一个基准元素,然后将数组分成左右两个区间,左区间比基准元素小,右区间比基准元素大。然后递归的去左区间和有区间排序,这种做法是将数组分成了两份。但是对于重复元素非常多的数组即使使用快速排序也会超时。因此这里我们学习新的划分方法,将数组划分成三份。
还是选一个基准元素将数组划分成三份,左区间元素都比基准元素小。中间区间元素和基准元素相同,右区间元素都比基准元素大。因为中间都是等于key的一定就是在最终位置,所以接下来递归还是只考虑左区间和右区间。
2.颜色分类
题目链接:75. 颜色分类
题目分析:
说起来这道题并不是真正的分治快速排序,而是把数组按照一定规则划分成三块的。当把这道题解决后,快排写的就非常简单。
这道题就相当于选择一个基准元素1,把小于1的放左边,大于1的放右边,等于1的放中间。
算法原理:
双指针可以将数组分成两块,具体怎么分,双指针系列第一道题移动零。这里我们需要三个指针将数组分成三块!
每个指针的作用:
i指针:遍历整个数组
left:标记 0 区域的最右侧
right:标记 2 区域的最左侧
三个指针将数组分成4份:
[0,left] :全都是0
[left+1,i-1]:全都是1
[i,right-1]:待扫描的元素
[rigth+1,n-1]:全都是2
接下来就讨论nums[i]是0或1或2应该怎么办?
当nums[i]为0的时候,要把0加入到左边区域,left指向的是 0 最右侧区域,此时left+1,然后将 i 位置和 left+1 元素交换,然后i+1。
还有一种极端情况 i 就在 left+1的为位置,并且正好是0。但是这种处理方法和上面一样。
当nums[i]为1的时候,i 指针往后走就行了
当nums[i]为2的时候,我们要将2加入到右边区间,也就是加入到 right - 1 的位置。交换 i 位置和 right -1 位置的元素。但是此时需要注意的是 交换给 i 位置的元素是待扫描的元素,因此 i 指针不能往后走!
class Solution {
public:void sortColors(vector<int>& nums) {int n = nums.size();int i = 0, left = -1, right = n;while(i < right){if(nums[i] == 0)swap(nums[++left], nums[i++]);else if(nums[i] == 2)swap(nums[--right], nums[i]);else++i;}}
};
3.排序数组
题目链接:912. 排序数组
题目描述:
算法原理:
在数组中选择一个基准元素key,根据key将数组分成左右区间,左区间元素小于等于key,右区间元素大于key。这个key就处于排序的最终位置。然后在将左区间排排序,右区间排排序,重复上述过程。整体就有序了。时间复杂度(nlogn)
但是如果数组都是重复元素,此时选择基准元素间将数组分成左右两区间就不行了。时间复杂度退化成O(n^2)
所以我们学习一个更优的做法,将 数组分三块 思想来实现快速排序
我们先选一个基准元素key,将数组分成三块。左区间小于key,中间区间等于key,右区间大于key。中间区间已经在排序后的最终位置,所以只用去去左区间排序,右区间排序。重复上述过程,整体就有序了。
数组如何分三块和颜色分类一模一样。定义一个i 指针 扫描数组,left指针 指向左区间小于key的最右侧, right指针 指向右区间大于key的最左侧。然后分情况讨论就好了。
即使数组全部都是重复元素,我们经过一次数组划分,整个数组都是中间区间,左右区间不存在,也不用在递归下去了,直接结束。时间复杂度O(n)
优化:用随机的方式选择基准元素
之前常用的三数取中,还是不够随机。要想时间复杂度逼近O(nlogn)就要用随机的方式选择基准元素。
随机选择就是让数组中每个元素被选择的概率相同,然后返回被选择的元素。
使用产生随机数的函数 rand(),让生成的随机数%这个区间的长度,然后加上left,这是在这个区间内的随机数的下标,然后返回对应下标的元素。
class Solution {
public:vector<int> sortArray(vector<int>& nums) {srand((unsigned int)time(nullptr));QuickSort(nums,0,nums.size()-1);return nums;}void QuickSort(vector<int>& nums, int l, int r){if(l >= r) return;//数组分三块int key = getRandom(nums, l ,r);int i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key)swap(nums[++left], nums[i++]);else if(nums[i] == key)++i;elseswap(nums[--right], nums[i]);}QuickSort(nums, l , left);QuickSort(nums, right, r);}int getRandom(vector<int>& nums, int left, int right){return nums[rand() % (right - left + 1) + left];}
4.数组中的第K个最大元素
题目链接:215. 数组中的第K个最大元素
题目分析:
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。其实就是一个TopK问题。
TopK问题四种问法:
第 k 个最大的元素
第 k 个最小的元素
前 k 个最大的元素
前 k 个最小的元素
可以使用堆排序, 时间复杂度O(nlogn)
还有一种就是快速选择算法,快速选择算法是基于快排实现的。时间复杂度O(n)。
算法原理:
一定要把数组分三块+随机选择基准元素掌握,才能懂这道题。
核心操作还是选择一个基准元素key,将数组分成< key , = key ,> key 三块区域。在这道题中我们是要找到第K大元素,这个第K大元素有可能落在三个区域中的任何一个区域。如果有一种方法能够确定第K大元素能够落在那个区域,那另外两个区域就不用考虑了。仅需在确定的区域里面递归找。所以说它是比快排更快的一种算法。
接下来重点就是如何确定第K大元素落在左边区域、中间区域、还是右边区域。
此时我们先统计出每个区域中元素的个数,假设左边区域元素个数为 a,中间区域元素个数为 b,右边区域元素个数为 c。
此时就分三种情况讨论:
因为求第K大,所以可以先考虑右边区域,因为右边区域都是大元素聚集地,第K大最有可能在右边区域。
- 第一种情况:如果第K大是落在右边区域,此时 c >= K,因为c表示大元素有多少个,而K表示找第K大的元素。如果 c >= K ,那第K大一定是落在右边区域。此时我们仅需到[right,r],找第K大。
- 第二种情况:如果到了第二情况那第一种情况一定是不成立的。如果第K大是落在中间区域,此时 b + c >= K,又因为第一种情况不满足,所有第K大一定是落在中间区域。此时就找到了也不用递归了。直接返回就可以。
- 第三种情况:第一、第二种情况全部不成立,第K大一定落在左边区域,去**[l,left]找**,但是此时并不是去找第K大了,本来是想在整个区间找第K大,但是第K大元素确定不在中间区域和右边区域,中间和右边区域都要被抛弃,此时去找左边区间找的是第 K - b - c 大的元素
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {srand((unsigned int)time(nullptr));return QuickSort(nums,0,nums.size()-1,k);}int QuickSort(vector<int>& nums, int l, int r, int k){//不用考虑区间不存在的情况,因为下面的判断K落在那个区域,只要满足进入的一定是有的if(l == r) return nums[l];// 1.随机选择基准元素int key = GetRandom(nums, l, r);// 2.根据基准元素将数组分三块int i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) ++i;else swap(nums[--right], nums[i]);}//3.计算每个区间都有多少元素,然后选择区间递归int b = right - 1 - left , c = r - right + 1; if(c >= k) return QuickSort(nums, right, r ,k);else if(b + c >= k) return key;else return QuickSort(nums, l, left, k - b - c);}int GetRandom(vector<int>& nums, int left, int right){return nums[rand() % (right - left + 1) + left];}// int findKthLargest(vector<int>& nums, int k) {// //前k个建小堆// priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k);// //N-k与堆顶元素比较,大于堆顶就入堆,再次调整成小堆// for(size_t i=k;i<nums.size();++i)// {// if(nums[i]>pq.top())// {// pq.pop();// pq.push(nums[i]);// }// }// return pq.top();// }
};
5.库存管理 III
题目链接:LCR 159. 库存管理 III
题目分析:
实际上这也是一个TopK问题,让找前K个最小元素。注意返回结果并不考虑顺序问题。
算法原理:
解法一:排序 ,时间复杂度O(nlogn)
解法二:堆 ,时间复杂度O(nlogk)
解法三:快速选择算法,时间复杂度O(n)
数组分三块+随机选择基准元素。
选择一个基准元素key,将数组分成< key , = key ,> key 三块区域。找前K个最小的元素,落在三个区域中任何一个。统计除每个区域元素个数,然后选择去那个区域找。
分三种情况:
因为前K下最小元素最有可能出现在左边区域,因此先判断左边区域
- a >= K ,去[l,left] 找前K个最小元素
- b + a >= K ,直接返回
- 1、2都不成立,去[right,r] 找 K - a - b 个最小元素
class Solution {
public:vector<int> inventoryManagement(vector<int>& nums, int k) {srand((unsigned int)time(nullptr));QuickSort(nums, 0, nums.size() - 1, k);return {nums.begin(),nums.begin() + k};}void QuickSort(vector<int>& nums, int l, int r, int k){if(l >= r) return;// 1. 随机选择基准元素int key = GetRandom(nums, l, r);// 2. 数组分三块int i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) ++i;else swap(nums[--right], nums[i]);}// 3. 分情况讨论int a = left - l + 1, b = right - left - 1;if(a >= k) QuickSort(nums, l, left, k);else if(a + b >= k) return;else QuickSort(nums, right, r, k - a - b);}int GetRandom(vector<int>& nums, int left, int right){return nums[rand() % (right - left + 1) + left];}
};
相关文章:

【基础算法总结】分治—快排
分治—快排 1.分治2.颜色分类3.排序数组4.数组中的第K个最大元素5.库存管理 III 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.分治 分治…...

[C++]——同步异步日志系统(1)
同步异步日志系统 一、项⽬介绍二、开发环境三、核心技术四、环境搭建五、日志系统介绍5.1 为什么需要日志系统5.2 日志系统技术实现5.2.1 同步写日志5.2.2 异步写日志 日志系统: 日志:程序在运行过程中,用来记录程序运行状态信息。 作用&…...

python 第6册 辅助excel 002 批量创建非空白的 Excel 文件
---用教授的方式学习 此案例主要通过使用 while 循环以及 openpyxl. load_workbook()方法和 Workbook 的 save()方法,从而实现在当前目录中根据已经存在的Excel 文件批量创建多个非空白的Excel 文件。当运行此案例的Python 代码(A002.py 文件࿰…...

力扣61. 旋转链表(java)
思路:用快慢指针找到最后链表k个需要移动的节点,然后中间断开节点,原尾节点连接原头节点,返回新的节点即可; 但因为k可能比节点数大,所以需要先统计节点个数,再取模,看看k到底需要移…...

智慧园区综合平台解决方案PPT(75页)
## 智慧园区的理解 ### 从园区1.0到园区4.0的演进 1. 园区1.0:以土地经营为主,成本驱动,提供基本服务。 2. 园区2.0:服务驱动,关注企业成长,提供增值服务。 3. 园区3.0:智慧型园区ÿ…...
Python只读取Excel文件的一部分数据,比如特定范围的行和列?
如何只读取Excel文件的一部分数据,比如特定范围的行和列? 在Python中,如果你只想读取Excel文件的特定范围,可以使用以下方法: pandas: Pandas是一个强大的数据处理库,它有一个内置函数read_excel()用于读…...

快速入门FreeRTOS心得(正点原子学习版)
对于FreeROTS,我第一反应想到的就是通信里的TDM(时分多址)。不同任务给予分配不同的时间间隔,也就是任务之间在每个timeslot都在来回切换。 这里有重要的一点,就是中断要短小,优先级是自高到底进行打断。 …...

【博主推荐】HTML5实现简洁好看的个人简历网页模板源码
文章目录 1.设计来源1.1 主界面1.2 关于我界面1.3 工作经验界面1.4 学习教育界面1.5 个人技能界面1.6 专业特长界面1.7 朋友评价界面1.8 获奖情况界面1.9 联系我界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,…...
Android应用安装过程
Android 系统源码源码-应用安装过程 Android 中应用安装的过程就是解析 AndroidManifest.xml 的过程,系统可以从 Manifest 中得到应用程序的相关信息,比如 Activity、Service、Broadcast Receiver 和 ContentProvider 等。这些工作都是由 PackageManage…...
Word中输入文字时,后面的文字消失
当在Word中输入文字时,如果发现后面的文字消失,通常是由以下3个原因造成的: 检查Insert键状态:首先确认是否误按了Insert键。如果是,请再次按下Insert键以切换回插入模式。在插入模式下,新输入的文字会插入…...
【LeetCode】合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 解题思路 水题,主要用于后面的链表的归并排序做了该题 AC代码 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nex…...
分子AI预测赛Task1笔记
分子AI预测赛Task1笔记 实践步骤:跑通baseline → 尝试个人idea→尝试进阶baseline 一、跑通baseline 1、应当先下载数据库 下载相应的数据库 !pip install lightgbm openpyxl2、训练模型并预测结果 首先要导入相应的库和方法类,如pandas等 # 1. …...

ubuntu 安装并启用 samba
环境:ubuntu server 24.04 步骤如下: sudo apt update sudo apt install samba修改配置文件: sudo vi /etc/samba/smb.conf新增内容: [username]path /home/[username]available yesvalid users [username]read only nobrow…...
atcoder ABC 357-D题详解
atcoder ABC 357-D题详解 Problem Statement For a positive integer N, let VN be the integer formed by concatenating N exactly N times. More precisely, consider N as a string, concatenate N copies of it, and treat the result as an integer to get VN. For…...

从单一到多元:EasyCVR流媒体视频汇聚技术推动安防监控智能升级
随着科技的飞速发展,视频已成为我们日常生活和工作中的重要组成部分。尤其在远程办公、在线教育、虚拟会议等领域,视频的应用愈发广泛。为了满足日益增长的视频需求,流媒体视频汇聚融合技术应运而生,它不仅改变了传统视频的观看和…...
Spring MVC数据绑定和响应——数据回写(二)JSON数据的回写
项目中已经导入了Jackson依赖,可以先调用Jackson的JSON转换的相关方法,将对象或集合转换成JSON数据,然后通过HttpServletResponse将JSON数据写入到输出流中完成回写,具体步骤如下。 1、修改文件DataController.java,在…...

怎么快速给他人分享图片?扫描二维码看图的简单做法
现在通过二维码来查看图片是一种很常见的方法,通过二维码来查看图片不仅能够减少对手机存储空间的占用,而且获取图片变得更加方便快捷,只需要扫码就能够查看图片,有利于图片的展现。很多的场景中都有图片二维码的应用,…...

【UML用户指南】-26-对高级行为建模-状态图
目录 1、概念 2、组成结构 3、一般用法 4、常用建模技术 4.1、对反应型对象建模 一个状态图显示了一个状态机。在为对象的生命期建模中 活动图展示的是跨过不同的对象从活动到活动的控制流 状态图展示的是单个对象内从状态到状态的控制流。 在UML中,用状态图…...

解决VSCode无法用ssh连接远程服务器的问题
原因: 因为windows自带的ssh无法连接远程服务器,需要用git底下的ssh.exe。 搜了很久,试过很多方法,包括替换掉环境变量中的ssh,但是都无效,最后发现是要在VSCode中配置需要使用哪个ssh.exe。 步骤&#…...

【区块链+基础设施】银联云区块链服务 | FISCO BCOS应用案例
为了顺应区块链基础设施化的发展趋势,中国银联推出了银联云区块链服务——UPBaaS,为金融行业采用区块链 技术提出了解决方案,微众银行为平台提供 FISCO BCOS 区块链开源技术支持。通过银联云区块链服务,用户可 以用可视化的方式创…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...