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] == 1curr++
  • 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算法详解相关推荐

  1. 快排亲兄弟:快速选择算法详解

    后台回复进群一起刷力扣???? 点击下方卡片可搜索文章???? 读完本文,可以去力扣解决如下题目: 215.数组中的第 K 个最大元素(Medium) 快速选择算法是一个非常经典的算法,和快速排序算法 ...

  2. 十大经典排序算法-快速排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

  3. Matlab人脸检测算法详解

    这是一个Matlab人脸检测算法详解 前言 人脸检测结果 算法详解 源代码解析 所调用函数解析 bwlabel(BW,n) regionprops rectangle 总结 前言 目前主流的人脸检测与 ...

  4. 图论-最短路Dijkstra算法详解超详 有图解

    整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...

  5. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

  6. 粒子群(pso)算法详解matlab代码,粒子群(pso)算法详解matlab代码

    粒子群(pso)算法详解matlab代码 (1)---- 一.粒子群算法的历史 粒子群算法源于复杂适应系统(Complex Adaptive System,CAS).CAS理论于1994年正式提出,C ...

  7. 基础排序算法详解与优化

    文章图片存储在GitHub,网速不佳的朋友,请看<基础排序算法详解与优化> 或者 来我的技术小站 godbmw.com 1. 谈谈基础排序 常见的基础排序有选择排序.冒泡排序和插入排序.众 ...

  8. 目标检测 RCNN算法详解

    原文:http://blog.csdn.net/shenxiaolu1984/article/details/51066975 [目标检测]RCNN算法详解 Girshick, Ross, et al ...

  9. Twitter-Snowflake,64位自增ID算法详解

    Twitter-Snowflake,64位自增ID算法详解 from: http://www.lanindex.com/twitter-snowflake%EF%BC%8C64%E4%BD%8D%E8 ...

最新文章

  1. 【计算机网络】数据链路层 : 局域网基本概念 ( 局域网分类 | 拓扑结构 | 局域网特点 | 局域网传输介质 | 介质访问控制方法 | IEEE 802 | 链路层 LLC、MAC 控制子层 )
  2. 全民app使用率排行榜统计全了,微信再次位居榜首!
  3. 插入数据,已存在则不插入
  4. SSH-permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
  5. Ubuntu 20.10安装docker
  6. React 单文件上传和多文件上传的封装
  7. 用ajax获取淘宝关键字接口
  8. 自定义音乐播放器的歌词显示view
  9. dsoframer java_DSOFramer的使用
  10. 计算机制图的相关标准,机械制图国家标准与计算机绘图.docx
  11. 黑马49期 day06-mysql入门(对照视频整理的一份笔记--有改动)
  12. Win10卸载KB5014699补丁教程
  13. 免费的可视化Web报表工具,JimuReport v1.5.0版本发布
  14. [动态系统的建模与分析]15_伯德图,bode图,为什么是20logM?分贝又是什么?
  15. Java 获取当前年 、当前月
  16. BZOJ2719 - [Violet 4]银河之星 (记忆化搜索+hash)
  17. 长时间戴耳机选哪一种、目前最好用的骨传导耳机品推荐
  18. mysql修改工具下载_MDB数据库修改工具
  19. 关于STM32软硬件兼容性相关的知识
  20. Excel无法进行公式计算

热门文章

  1. java实现ln10_Java程序员从笨鸟到菜鸟之(三十)javascript弹出框、事件、对象化编程...
  2. 实力认证 | 得帆入选《2022中国低/无代码市场研究及选型评估报告》
  3. 蚂蚁区块链第20课 可信存证司法链从入门到实施
  4. 使用GPU Instancing屏幕花屏问题
  5. 苹果为什么这么红?——美国之行总结短评之一
  6. pycharm分屏设置
  7. Flutter 返回按钮的监听
  8. 使用SQL语句中的Group by分组并计算每组的数量
  9. Luogu4168 蒲公英 (分块)
  10. 国家网络安全宣传周之代表厂商盘点——上海浪擎引领国内灾备产业发展潮流...