找第k小的数
问题描述
给定一个数组A = A[1,...,n]
和一个下标i(1 <= i <= n)
,找出数组A内第i
小的数。
例如i=1
则是找到最小的数,i=n
则是找到最大的数。
解决办法
1. 将数组升序排序,然后遍历取出第i
个数即为所求。
2. 如果数组的取值范围波动不大,则可以通过用空间换取时间的方式来求解。即
Algorithm : findKTh(A,k)
1. 申请一个大小为max(A) + 1的数组B,依次遍历数组A,将A中的值作为B中的下标,值为1。
如A[1,3],则B = new int[4]. b[0]=0,b[1]=1,b[2]=0,b[3]=1。
2. 遍历数组B,第k个值为1的数即为所求。
3. 利用中位数的中位数求解(复杂度为O(n))。由于我们只需要求第i小的数(仅一个数),没必将数组完全排序。
Algorithm : findKTh(A,k)
1. 将输入数组的n个数分割为Math.ceil(n/5)数组,每个数组个数是5。(可能有一个数组的个数是n%5)
2. 步骤1所得的数组个数为
1. 1个,则求该数组的中位数即为中位数的中位数。
2. 大于1个,则分别求出每个数组的中位数。然后将将所有的中位数作为入参执行步骤1。
3. 以步骤2的结果为pivot,进行Partition.(算法导论7.1章)
4. 设步骤3Partition所得结果中,pivot的位置为i
if k = i then return x.
else,if k < i, 递归调用findKth(A[1,...,i-1],i)
else,if k > i, 递归调用findKth(A[i+1,...],k-i)
算法备注
三个数中取中位数(最多三次比较)
algorithm : findMedian(a,b,c)
1. if a > b , then swapValue(a,b)
2. if c < a , return a
if c > b , return b
else , return c
四个数取中位数(四次比较,默认第二小为中位数)
algorithm : findMedian(A[a,b,c,d])
1. if a > b , then swapValue(a,b) //保证 a<b
2. if c > d , then swapValue(c,d) //保证 c<d
3. if a > c , then swapValue(b,d),swapValue(a,c) //c是最小值,不是中位数。保证a<b c<d a<c
4. if b < c , return b
else return c
五个数中取中位数()
algorithm : findMedian(A[a,b,c,d,e])
1. if a > b , then swapValue(a,b) //保证 a<b
2. if c > d , then swapValue(c,d) //保证 c<d
3. if a > c , then swapValue(b,d),swapValue(a,c) //c是最小值,不是中位数。保证a<b c<d a<c
4. if b > e , then swapValue(b,e)
5. if b > c , then swapValue(b,c)
6. if c > e , then swapValue(c,e)
else, return c
算法代码
参考