找第k小的数

找第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]=12. 遍历数组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个,则分别求出每个数组的中位数。然后将将所有的中位数作为入参执行步骤13. 以步骤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

算法代码

java 示例代码

参考

MIT分析设计算法

点赞