更多精彩文章,请关注公众号【程序员小熊】。

排序算法不论是在刷题还是面试都经常遇到,掌握它能提升自己的算法功力从而增加自己面试通过的几率。

本文主要介绍一下三路快排,并以微软的一道面试题 leetcode 75. 颜色分类作为例题来讲解,供大家参考,希望对大家有所帮助。

三路快排

使用快速排序的思想给带有大量的重复键值的数组进行排序,一种经典的实现方式就是三路快排(Quick Sort 3 Ways)。

主要思想

整个数组分成三部分,即小于 v、等于 v 和大于 v。分割后在递归的过程中,只需要递归地对小于 v 和大于 v 的部分进行快速排序,不关心等于 v 的部分。如下图示。

1、将数组分为三部分,索引 lt 指向小于 v 的最后一个元素的位置,所以 nums[l+1...lt] < v,即区间 [l+1, lt] 中的元素均小于 v。同理索引 gt 指向大于 v 的第一个元素的位置 ,所以 nums[gt...r] > v,lt 和 gt 分别是 less than 和 greater than 的缩写。

2、当前需要处理的元素为 i 位置的元素 k,保证 nums[lt+1...i-1] == v。如果 k == v,将 k 纳入等于 v 的部分,i 右移继续遍历。

3、如果 k < v,只需要将该元素与等于 v 的第一个元素交换位置,此时元素 k 处于小于 v 的最后一个元素,相应地 lt 向右移动一位,i 继续右移,查看下一个元素。

4、如果此时 k > v,只需要将该元素与 gt - 1 对应的元素交换位置,此时元素 k 处于数组大于 v 的第一个元素,相应地 gt 向左移动一位,指向大于 v 的第一个位置。

5、排序完成之后,数组如下图示意,lt 和 gt 分别指向小于 v 的最后一个位置和大于 v 的第一个位置,最后交换 l 位置的元素跟 lt 位置的元素,之后只需要对小于 v 和大于 v 的部分进行递归快速排序,等于 v 的部分已经放在数组中合适的位置。

优点:不需要对大量等于 v 的元素进行重复操作,可以少考虑很多元素,特别是对于等于 v 的元素特别多的话,这一步优化变得非常明显。

75. 颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

示例 1:

输入:nums = [2,0,2,1,1,0]

输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]

输出:[0,1,2]

解题思路

由于排序后的数组主要依次分成三部分,即等于 0 的部分、等于 1 的部分和等于 2 的部分,这不是很像上面讲的三路快速排序吗?
每次选取一个标定点,由于数组中有很多个与标定点相等的元素,所以将数组分成三部分,即小于 v、等于 v 和大于 v,然后递归地对小于 v 和大于 v 的地方进行三路快排。

由于当前数组只有三个元素,所以只需要对整个数组执行一次三路快排即可。如下图示。

保证在遍历整个数组的过程中,0 处在整个数组的开始位置、1 处在紧接着 0 后面的位置,2 处在整个数组的末尾位置。

1、设置索引 zero 和 two,使得数组 nums[0...zero] == 0 和 nums[two...n-1] == 2,设置遍历索引 i 用于遍历数组元素,保证了 nums[zero+1...i-1] == 1。

2、当遍历到元素 m 时,如果 m == 1,此时只需将 m 纳入到属于 1 的部分,同时 i 右移。

3、如果 m == 2,只要取出索引 two 指向的元素的前一个元素 k(当前不等于 2 的第一个元素),与 m 进行交换位置,并将索引 two 左移一位,相当于将此时的 m 纳入到属于 2 的部分。

4、如果 m == 0,只需要找到索引 zero + 1 对应的元素(当前值为 1的第一个元素),将其与当前的 m 交换位置,并将 zero 右移,相当于将此时的 m 纳入到属于 0 的部分,将索引 i 右移查看下一元素的值。

Show me the Code

// c++
void sortColors(vector<int>& nums) {int zero = -1; // 保证下标0到zero对应的元素都为0int two = nums.size(); // 保证下标two到numsSize-1对应的元素都为 2for (int i = 0; i < two;) {// 直接将遍历到的元素1纳入到属于1的部分,i右移继续遍历if (nums[i] == 1) {i++;}// 交换下标为two前一下标对应的元素与遍历到的元素// 并将遍历到的元素2纳入到属于2的部分,two左移else if (nums[i] == 2) {swap(nums[i], nums[--two]);}// 交换下标为zero后一下标对应的元素与遍历到的元素// 并将遍历到的元素0纳入到属于0的部分,zero和i右移else {swap(nums[++zero], nums[i++]);}}
}
// go
func sortColors(nums []int)  {zero, two := -1, len(nums)for i := 0; i < two; {if nums[i] == 1 {i++} else if nums[i] == 2 {two -= 1nums[i], nums[two] = nums[two], nums[i]} else {zero += 1nums[i], nums[zero] = nums[zero], nums[i]i++}}
}

往期精彩回顾

你管这破玩意叫“对撞指针”?

更多精彩

关注公众号 『 程序员小熊 』,回复【算法】或【python】即可获取高清无码的经典算法python 电子书~

史上最清晰的三路快速排序相关推荐

  1. 史上最清晰的函数空间讲解

    史上最清晰的函数空间讲解 1.什么是数学的空间? 数学的空间定义了研究工作的对象和遵循的规则,研究工作的对象在空间中称之为元素,遵循的规则在空间中称之为结构,结构有线性结构(加法和数乘)和拓扑结构(距 ...

  2. 单链表-史上最清晰的尾插法和头插法

    02.单链表-史上最清晰的尾插法和头插法 1.单链表 链表是一系列的存储数据元素的单元,通过指针(引用)串联起来的,因此每个单元至少有两个域,一个域用于数据元素的存储,另一个域是指向其他单元的指针. ...

  3. 史上最清晰的Java内存模型介绍

    这篇文章的标题看起来很霸气,于是我毫不犹豫转了~并且同样起了个霸气侧漏的标题! 本文转载自:再有人问你Java内存模型是什么,就把这篇文章发给他. 网上有很多关于Java内存模型的文章,在<深入 ...

  4. C# 直接选择排序(史上最清晰,最通俗)

    public void SelectSort(int[] array) { int len = array.Length; int minValIndex; //无序区中最小值的索引 int i; / ...

  5. 史上最清晰的红黑树讲解(上)(转自CarpenterLee,纯学习用)

    本文以Java TreeMap为例,从源代码层面,结合详细的图解,剥茧抽丝地讲解红黑树(Red-Black tree)的插入,删除以及由此产生的调整过程. 总体介绍 Java TreeMap实现了So ...

  6. 史上最清晰的红黑树讲解(上)

    本文github地址 本文以Java TreeMap为例,从源代码层面,结合详细的图解,剥茧抽丝地讲解红黑树(Red-Black tree)的插入,删除以及由此产生的调整过程. 总体介绍 Java T ...

  7. sensei鼠标测试软件,【SteelSeriesSenseiMLG限量版游戏鼠标评测】史上最清晰完整 游戏鼠标微动更换教程-中关村在线...

    01旗舰鼠标难逃故障 自己动手修复 [中关村在线]SteelSeriesSenseiMLG限量版游戏鼠标评测: [中关村在线键鼠频道原创] 玩家进行游戏操作时,其鼠标点击.移动频率,要远高于普通用户日 ...

  8. 史上最清晰ufo视频 土耳其新闻

    工作之余,我们也要轻松轻松嘛   ~@^_^@~ 下载看看了 宇宙太大了,我想除了地球,应该还有有生命的星球

  9. 查找(一)史上最简单清晰的红黑树讲解 http://blog.csdn.net/yang_yulei/article/details/26066409

    查找(一)史上最简单清晰的红黑树讲解 2014-05-18 00:05 4037人阅读 评论(6) 收藏 举报 分类: 数据结构(7) 算法(4) 版权声明:本文为博主原创文章,未经博主允许不得转载. ...

最新文章

  1. 使用Fiddler抓取手机HTTP流量包
  2. 【IntelliJ idea/My/ecplise】启动项目前,修改配置JVM参数
  3. SOA面向服务架构打包部署
  4. python break -else 语句
  5. 服务器机房有哪些重要系统
  6. python取反函数_Python优雅的反函数int(string,base)
  7. java synchronized wait
  8. jzoj4249-游戏【贪心】
  9. 获取 Windows 窗体 DataGridView 控件中选定的单元格、行和列
  10. 自己写一个java.lang.reflect.Proxy代理的实现
  11. 计算机是如何工作的,Java多线程编程
  12. DCOS Virtual Networks
  13. word计算机基础知识试题及答案,计算机基础知识试题及答案(一)
  14. 使用RNA-seq数据通过网络熵评估肿瘤内异质性
  15. 桃花、杏花、梨花、李花傻傻分不清?快来学习吧
  16. 塔防类游戏 ——简单的角色合并逻辑示例
  17. 从百度世界大会2014中所看到,所感受到的
  18. 【无限互联】学员作品 豆果美食IOS客户端
  19. 深度之眼Pytorch打卡(十三):Pytorch全连接神经网络部件——线性层、非线性激活层与Dropout层(即全连接层、常用激活函数与失活 )
  20. DPlayer播放m3u8

热门文章

  1. HTML5学习资料推荐
  2. u盘装linux运行慢,从U盘安装Linux的一点心得体会
  3. 【MM32F5270开发板试用】快速移植STM32应用到MM32F5270(以OLED为例)
  4. 六成大学生认为自己毕业10年内会年入百万!网友:知乎上多了,没被社会毒打过吧!...
  5. 计算机毕业设计ssm免费音乐分享平台
  6. 超详细的(视频)人脸情感特征提取教程【Python】
  7. 【MySQL】如何使用MySQL锁(全局锁、表级锁、行级锁)?
  8. jdbc与jdbctemplate区别
  9. 二维码如何区分微信支付还是支付宝
  10. HTML与CSS网页开发基础快速入门