接前文,除了广泛使用在快速排序中。Partition算法还可以很容易的实现在无序序列中使用O(n)的时间复杂度查找kth(第k大(小)的数)。

同样根据二分的思想,每完成一次Partition我们可以轻松的知道该位置前面有几个比自己小的数,后面有几个比自己大的数(或逆序相反)。所以也能知道自己是第几大或者小的数。

查找kth(大/小)

func partition(left int, right int, arr []int) (int) {
i := left
j := right
pivot := arr[left]
for i != j {
for i < j && arr[j] >= pivot {
j--
} for i < j && arr[i] <= pivot {
i++
} if i < j{
arr[i], arr[j] = arr[j], arr[i]
}
}
arr[left], arr[i] = arr[i], arr[left]
return i
} func findKthSmallestNumber(arr[]int, k int) (int) {
left := 0
right := len(arr)-1
targetNumber := 0
for left <= right {
pos := partition(left, right, arr)
if pos == k-1 {
targetNumber = arr[pos]
break
} else if pos > k-1 {
right = pos - 1
} else {
left = pos + 1
}
}
return targetNumber
} func main() {
list := []int{4, 3, 1, 4, 5, 6, 3}
fmt.Println(findKthSmallestNumber(list, 6))
}

逻辑是每次partition回传的位置,都是分割好的位置。

那么我们假设默认pivot设置的数总是操作数组(假如是按照正序排列,即比pivot大的数放右边,比pivot小的数放左边)的第一个数。分割完毕后,我们拿着回传的pivot位置同要寻找的k小的数做比较。

如果 pivot = k-1 那么说明这就是我们要找的那个位置,直接返回即可。pivot返回的是索引位置,比如我们要找第二小的数,索引位置就应该是1。

如果 pivot > k-1 那么说明我们要找的数在pivot的左边,这时我们需要将right置为pos索引-1

如果 pivot < k-1 那么说明我们要找的数载pivot的右边,这时我们需要将left的值置为pos索引+1

另外特别要注意的一点就是边界的问题。由于上面我使用的例子中right就是传递的索引的终点为之,所以left是有可能等于right的情况的,这时要让程序进入循环正确退出。如果你使用的是len数量版本的partition算法,就不需要这样做。

Dutch national flag problem:

荷兰国旗问题,同样是经典的Partition算法的问题。通过一次扫描来进行归类,依然是他核心思想。解决这个问题我们除了要同时使用头部指针,尾部指针以外。还需要使用一个当前位置的指针来扫描。

func threeWayPartition(list []int, target int) {
var smallestPos, scanPos int
biggestPos := len(list)-1 for scanPos <= biggestPos {
if list[scanPos] < target {
list[scanPos], list[smallestPos] = list[smallestPos], list[scanPos]
scanPos++
smallestPos++
} else if list[scanPos] > target {
list[scanPos], list[biggestPos] = list[biggestPos], list[scanPos]
biggestPos--
} else {
scanPos ++
}
}
}

首先扫描的当前位置只能小于和等于指向最大指针的位置。因为我们总是使用scanPos位置上的数来进行判断的,如果这里是小于而不是小于等于的话就意味着指向最大值的指针位置所在的值miss了。

说明这个之后,其他的就可以分为三种情况。

如果scanPos > target的话 就会跟后面指向大值的指针交换,然后大值指针往后退一

如果scanPos < target的话 就会跟前面指向小值的指针交换,然后当前指针位置和指向最小值的指针同进一

如果scanPos = target的话 当前指针继续往前,指向小值的指针会原地不动。

用心感受一下,其实还是蛮简单的。。

Partition算法以及其应用详解下(Golang实现)的更多相关文章

  1. Partition算法以及其应用详解上(Golang实现)

    最近像在看闲书一样在看一本<啊哈!算法> 当时在amazon上面闲逛挑书,看到巨多人推荐这本算法书,说深入浅出简单易懂便买来阅读.实际上作者描述算法的能力的确令人佩服.就当复习常用算法吧. ...

  2. python 排序算法总结及实例详解

    python 排序算法总结及实例详解 这篇文章主要介绍了python排序算法总结及实例详解的相关资料,需要的朋友可以参考下 总结了一下常见集中排序的算法 排序算法总结及实例详解"> 归 ...

  3. SSL/TLS协议详解(下)——TLS握手协议

    本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...

  4. [js高手之路]深入浅出webpack教程系列3-配置文件webpack.config.js详解(下)

    本文继续接着上文,继续写下webpack.config.js的其他配置用法. 一.把两个文件打包成一个,entry怎么配置? 在上文中的webpack.dev.config.js中,用数组配置entr ...

  5. SSD算法及Caffe代码详解(最详细版本)

    SSD(single shot multibox detector)算法及Caffe代码详解 https://blog.csdn.net/u014380165/article/details/7282 ...

  6. 红黑树原理详解及golang实现

    目录 红黑树原理详解及golang实现 二叉查找树 性质 红黑树 性质 operation 红黑树的插入 golang实现 类型定义 leftRotate RightRotate Item Inter ...

  7. 关联规则算法(The Apriori algorithm)详解

    一.前言 在学习The Apriori algorithm算法时,参考了多篇博客和一篇论文,尽管这些都是很优秀的文章,但是并没有一篇文章详解了算法的整个流程,故整理多篇文章,并加入自己的一些注解,有了 ...

  8. SSD(single shot multibox detector)算法及Caffe代码详解[转]

    转自:AI之路 这篇博客主要介绍SSD算法,该算法是最近一年比较优秀的object detection算法,主要特点在于采用了特征融合. 论文:SSD single shot multibox det ...

  9. CSS2.1SPEC:视觉格式化模型之width属性详解(下)

    本文承接CSS2.1SPEC:视觉格式化模型之width属性详解(上),继续分析CSS视觉格式化模型中width以及相关值的计算问题: 注:与上节不同,本节的demo中由于出现了float,absol ...

随机推荐

  1. UVA225-Golygons(dfs)

    Problem UVA225-Golygons Accept:307  Submit:3646 Time Limit: 3000 mSec  Problem Description Imagine a ...

  2. sqlalchemy和flask-sqlalchemy的几种分页方法

    sqlalchemy中使用query查询,而flask-sqlalchemy中使用basequery查询,他们是子类与父类的关系 假设 page_index=1,page_size=10:所有分页查询 ...

  3. SQLAlchemy中的自引用

    SQLALCHEMY采用adjacency list pattern来表示类的自引用. 例如,对于类Node自引用: class Node(Base): __tablename__='node' id ...

  4. IDEA+'mvn' 不是内部或外部命令

    问题描述: 提示'mvn' 不是内部或外部命令,也不是可运行的程序或批处理文件. 或者提示 The JAVA_HOME environment variable is not defined corr ...

  5. linux之dos2unix命令

    今天在使用脚本升级的时候碰到一个问题,然后写了一个简单的自测脚本进行测试,如上图,理论上应该输出 /usr/local/mysql/bin/mysqldump -h 127.0.0.1 -uroot ...

  6. Linux Namespace : Network

    Network namespace 在逻辑上是网络堆栈的一个副本,它有自己的路由.防火墙规则和网络设备.默认情况下,子进程继承其父进程的 network namespace.也就是说,如果不显式创建新 ...

  7. 第一次在新西兰组织技术社区活动:Monkeyfest2018

    从3月份登陆到现在,转眼间已经8个月了.在6个月的时候我就想写篇文总结下近期的一些状况,一直拖到现在.因为近期一直在筹备我第一次社区活动——Monkeyfest 2018,占用了比较多的时间.这是一个 ...

  8. RabbitMQ 3.6.1 升级至 3.7.9 版本(Windows 升级至Centos)

    随着公司业务量的增加,原本部署在Windows服务器的RabbitMQ集群(3.6.1)总是出现莫名其妙的问题,经查询官方Issue,确认是RabbitMQ 3.6.1 版本的bug.查看从3.6.1 ...

  9. centos安装RabbitMQ 3.7.9 (使用RPM)

    上篇我们提到不使用RPM安装RabbitMQ 3.7.8,其实我个人更倾向不使用RPM安装RabbitMQ,因为可以控制安装位置及设置参数. 存在即合理,使用RPM安装RabbitMQ,可以减少配置参 ...

  10. Randomized Online PCA Algorithms with Regret Bounds that are Logarithmic in the Dimension

    目录 Setup of Batch PCA and Online PCA Hedge Algorithm 改进算法 用于矩阵 \(rounding()\) 前俩次,都用到了\(rounding()\) ...