Partition算法详解
partition算法有着非常重要的应用,这个算法的思想虽然简单,但具体实现的细节却比较多,今天我重点复习了这个算法,本文记录我对这个算法的理解。
文章目录
- Partition算法解析
- 二分Partition
- 三分Partition
- 二分Partition应用
- 时间复杂度
- 代码
- 三分Partition应用
- 代码
Partition算法解析
二分Partition
快速排序作为非常著名的排序算法,其思想却很简单:每次从数组中选一个数作为pivot,然后将数组划分为2部分,小于等于pivot数的在其左边,大于等于pivot的数在其右边,然后分别对pivot的左边和右边进行递归。
二分partition的实现用到了双指针,left寻找一个比pivot大的数,right寻找一个比pivot小的数,然后交换它们,循环这一过程直到left == right
,将pivot放到这个位置。
注意: 如果pivot选的是最左的元素,则要先移动right;如果pivot选的是最右的元素,则要先移动left。
int partition(vector<int>& nums, int left, int right) {int pivot = nums[left], base = left;while (left < right) {while (left < right && nums[right] >= pivot) right--;while (left < right && nums[left] <= pivot) left++;swap(nums[left], nums[right]);}nums[base] = nums[left];nums[left] = pivot;return left;
}
三分Partition
三分partition自然就是把数组划分成3部分,小于pivot的在左边,等于pivot的在中间,大于pivot的在右边。
由于三分partition要保证中间的那部分,所以像二分partition那么划分是肯定不行的。为了解决这个问题,我们需要先定义循环不变量:
[0, zero)
内的元素都等于0[zero, curr)
内的元素都等于1[curr, two]
内的元素还未被检查(two, len - 1]
内的元素都等于2
我们用curr
来遍历数组,遍历的范围是[0, two]
。在整个遍历过程中,始终要保证循环不变量的正确,因此,当遇到0时,要与nums[zero]
交换,遇到2时,要与nums[two]
交换。
细节: 每次交换时,边界zero
或者two
自然是要相应地进行移动,那么curr
呢?
nums[curr] == 1
时,显然curr++
nums[curr] == 0
时,如果curr == zero
,那么由于zero
需要右移,curr
则也必须右移,否则curr < zero
,破坏了循环不变量;如果curr > zero
,此时nums[zero] == 1
,那么会把1交换到curr
的位置,即使不立即curr++
,下次循环时也会由于nums[curr] == 1
而curr++
nums[curr] == 2
时,num[two]
的值是不确定的,所以我们只进行交换和左移two
,不移动curr
初始化: 初始化要保证除了[curr, two]
外的3个区间都为空
二分Partition应用
我们以leetcode第215题:找数组中的第k个最大元素为例来说明二分partition算法在快速排序中的应用。
这道题虽然不是直接让我们进行快速排序,但我们可以想到,每次partition之后都会返回pivot最终在数组中的位置mid,如果mid就是要找的位置,那就不用再继续递归partition下去了,答案已经找到;否则,继续在mid的左边或者右边进行递归partition。
时间复杂度
快速排序的时间复杂度跟选取的pivot有关,如果每次都选最左边的作为pivot,而它刚好又是数组中最小的元素,那么这次partition需要遍历完整个数组,即遍历n次;接着递归右部分(有n-1个元素),如果同样最左边的是最小的,那么需要遍历n-1次…
如果每次都将数组划分成1和n-1两部分,每次又继续递归n-1的那部分,那么就会导致快排的最差时间复杂度:O(n2)O(n^2)O(n2)。
为了改善这种情况,可以随机选取pivot。
代码
class Solution {public:int findKthLargest(vector<int>& nums, int k) {srand(time(0));int left = 0, right = nums.size() - 1;int target = nums.size() - k;int mid = partition(nums, left, right);while (mid != target) {if (mid < target) {left = mid + 1;mid = partition(nums, left, right);}else {right = mid - 1;mid = partition(nums, left, right);}}return nums[mid];}
private:int partition(vector<int>& nums, int left, int right) {// 使用随机来加速快排, 效果明显int i = rand() % (right - left + 1) + left;swap(nums[i], nums[left]);int pivot = nums[left], base = left;while (left < right) {while (left < right && nums[right] >= pivot) right--;while (left < right && nums[left] <= pivot) left++;swap(nums[left], nums[right]);}nums[base] = nums[left];nums[left] = pivot;return left;}void swap(int& num1, int& num2) {int tmp = num1;num1 = num2;num2 = tmp;}
};
三分Partition应用
leetcode第75题:颜色分类就是一道典型的三分partition应用题。
代码
class Solution {public:void sortColors(vector<int>& nums) {int left = 0, right = nums.size() - 1;int curr = 0;while (curr <= right) {if (nums[curr] == 0) swap(nums[left++], nums[curr++]);else if (nums[curr] == 2) swap(nums[right--], nums[curr]);else curr++;}}
private:void swap(int& num1, int& num2) {int tmp = num2;num2 = num1;num1 = tmp;}
};
Partition算法详解相关推荐
- 快排亲兄弟:快速选择算法详解
后台回复进群一起刷力扣???? 点击下方卡片可搜索文章???? 读完本文,可以去力扣解决如下题目: 215.数组中的第 K 个最大元素(Medium) 快速选择算法是一个非常经典的算法,和快速排序算法 ...
- 十大经典排序算法-快速排序算法详解
十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...
- Matlab人脸检测算法详解
这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...
- 图论-最短路Dijkstra算法详解超详 有图解
整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...
- C++中的STL算法详解
1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...
- 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码
粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...
- 基础排序算法详解与优化
文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...
- 目标检测 RCNN算法详解
原文:http://blog.csdn.net/shenxiaolu1984/article/details/51066975 [目标检测]RCNN算法详解 Girshick, Ross, et al ...
- Twitter-Snowflake,64位自增ID算法详解
Twitter-Snowflake,64位自增ID算法详解 from: http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8 ...
最新文章
- 【计算机网络】数据链路层 : 局域网基本概念 ( 局域网分类 | 拓扑结构 | 局域网特点 | 局域网传输介质 | 介质访问控制方法 | IEEE 802 | 链路层 LLC、MAC 控制子层 )
- 全民app使用率排行榜统计全了,微信再次位居榜首!
- 插入数据,已存在则不插入
- SSH-permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
- Ubuntu 20.10安装docker
- React 单文件上传和多文件上传的封装
- 用ajax获取淘宝关键字接口
- 自定义音乐播放器的歌词显示view
- dsoframer java_DSOFramer的使用
- 计算机制图的相关标准,机械制图国家标准与计算机绘图.docx
- 黑马49期 day06-mysql入门(对照视频整理的一份笔记--有改动)
- Win10卸载KB5014699补丁教程
- 免费的可视化Web报表工具,JimuReport v1.5.0版本发布
- [动态系统的建模与分析]15_伯德图,bode图,为什么是20logM?分贝又是什么?
- Java 获取当前年 、当前月
- BZOJ2719 - [Violet 4]银河之星 (记忆化搜索+hash)
- 长时间戴耳机选哪一种、目前最好用的骨传导耳机品推荐
- mysql修改工具下载_MDB数据库修改工具
- 关于STM32软硬件兼容性相关的知识
- Excel无法进行公式计算
热门文章
- java实现ln10_Java程序员从笨鸟到菜鸟之(三十)javascript弹出框、事件、对象化编程...
- 实力认证 | 得帆入选《2022中国低/无代码市场研究及选型评估报告》
- 蚂蚁区块链第20课 可信存证司法链从入门到实施
- 使用GPU Instancing屏幕花屏问题
- 苹果为什么这么红?——美国之行总结短评之一
- pycharm分屏设置
- Flutter 返回按钮的监听
- 使用SQL语句中的Group by分组并计算每组的数量
- Luogu4168 蒲公英 (分块)
- 国家网络安全宣传周之代表厂商盘点——上海浪擎引领国内灾备产业发展潮流...