快排解决 topK/中位数 问题

前言

经常会有这种问题:
1.一个100万的无序数组,在接近复杂度内找到其中位数。
2.一个100万的无序数组,找到其第 K 大的数。

这种问题最常见,也最经常被问到!也有很多对应的解决方法。这里给出一种用快排来解决问题的方法!

快排

快排的性能在所有排序算法里面是最好的,数据规模越大快速排序的性能越优。快排在极端情况下会退化成 O(n^2) 的算法,因此假如在提前得知处理数据可能会出现极端情况的前提下,可以选择使用较为稳定的归并排序。

快排本质上是一种分治策略,在一次循环结束,会有哨兵把数组分成前半部分与后半部分。且以哨兵为界前半部分都不大于(小于)后半部分。

  • 如果哨兵恰好处于数组的中部时候那么哨兵就是整个数组的中位数。
  • 无论那次循环,哨兵都是整个数组的 topK(这里哨兵下标为K)

实现

package main

import (
	"fmt"
)

func getTopK(arr []int, k, left, right int) int {
	if left >= right {
		return arr[left]
	}

	tmp := arr[left]
	lpos := left
	rpos := right

	for lpos < rpos {
		for ; lpos < rpos && arr[rpos] >= tmp; rpos-- {
		}

		if lpos < rpos {
			arr[lpos] = arr[rpos]
			lpos++
		}

		for ; lpos < rpos && arr[lpos] <= tmp; lpos++ {
		}

		if lpos < rpos {
			arr[rpos] = arr[lpos]
			rpos--
		}
	}

	arr[lpos] = tmp
	if lpos == k {
		return arr[lpos]
	} else if lpos < k {
		return getMid(arr, k, lpos+1, right)
	} else {
		return getMid(arr, k, left, lpos-1)
	}
}


func main() {
	arr := []int{1, 3, 8, 2, 6, 9, 0, 5}
	for i := 0; i < len(arr); i++ {
		fmt.Printf("top %d is %d\n", i, getTopK(arr, i, 0, len(arr)-1))
	}
}

运行结果:

posted @ 2020-12-16 13:29  sinpo828  阅读(341)  评论(0编辑  收藏  举报