第K小算法
问题
给定长度为n的序列a和整数k∈[1,n],求出a中第k小的数。
解法一:半个快排
使用快排思路,每次随机找一个数当作pivot,小于pivot放左边,大于pivot放右边,然后根据k的大小决定去左边还是右边查找。复杂度期望O(n),最坏O(n2)。
代码
还是使用快排思路,这次用一个骚操作:
假设当前在找[l,r]内的第k小,即solve(l, r, k)。尝试找当前序列的pivot时,先将所有数5个一组分组,得到n/5个长度为5的子序列,对于每个子序列,找出中位数(这是O(1)的),得到一个长度为n/5的中位数序列,再递归调用solve(1, n/5, n/10)找到这个中位数序列的中位数,作为pivot。
这个pivot一定不小于n/10个中位数,也就是说不小于103n的数,同理也不大于103n的数。
写出递归表达式:
T(n)=T(107n)+T(51n)+O(n)
可以证明T(n)=O(n),证明如下:
-
n=1时,成立;
-
假设n≤k−1时满足T(n)≤B⋅n,则
T(k)=T(0.7k)+T(0.2k)+Ck=0.7Bk+0.2Bk+Ck=(0.9B+C)k
只要0.9B+C≤B就可以,也就是说B≥10C就行。取任意满足条件的B即可得出T(n)=O(n)。
不过观察到B∼10C,也就是说算法有个10的常数,可能常数会比较大。随机情况下,差不多慢三倍。
代码