数组中第K大的元素总结
解法1: 我们可以对这个乱序数组按照从大到小先行排序,然后取出前k大,总的时间复杂度为O(n*logn + k)。
解法2: 如果k很小,比如第五个最大的数,而整个数组的长度非常的大,那么,还有一种方法就是,我做k遍找最大的数,每做一遍,就把最大的放在数组的最后面(遍历一次找出最大的数例如冒泡,选择排序都可以。),然后减少数组扫描的范围,就可以把第k大的数找出来,这样做的复杂度就是O(K*N),在K很小的情况下,还是不错的。
解法3: 利用快速排序的思想,从数组S中随机找出一个元素X,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。第K大的元素在已排序数组中的下标应为index(第K大元素)=数组长度-1。记元素X的下标为index(x),当index(x)= index(第K大元素),表示找到结果,返回。
这时有两种情况:
1. index(x)> index(第K大元素),则继续在下标index(x)的左边找
2. index(x)> index(第K大元素),则继续在下标index(x)的右边找
解法4: 二分[Smin,Smax]查找结果X,统计X在数组中出现,且整个数组中比X大的数目为k-1的数即为第k大数。时间复杂度平均情况为O(n*logn)
解法5:用O(4*n)的方法对原数组建最大堆,然后pop出k次即可。时间复杂度为O(4*n + k*logn)
解法6:维护一个k大小的最小堆,对于数组中的每一个元素判断与堆顶的大小,若堆顶较大,则不管,否则,弹出堆顶,将当前值插入到堆中。时间复杂度O(n * logk)
解法7:利用计数排序的思想,,前面有k-1个数则为第k大数,平均情况下时间复杂度O(n)。
像解法3和6应该是比较常见的解法:
下面是解法3的java代码
package com.wj; /** * Created by wangjia . * Date:2015/9/5 0005 * Time:10:53 */ public class MaxK { /*找到划分点位置*/ int Sort(int[] arr, int low, int high) { int pivot = arr[low]; //这里每次的枢纽元素都取了待排数组的第一个元素,记住是a[low],而不是a[0] System.out.println("low-->"+low); while (low < high) //时间复杂度是O(n),n是数组长度 { while (arr[high] >= pivot && low < high){ high--; } if(low<high){ arr[low++] = arr[high]; } while (arr[low] < pivot && low < high){ low++; } if(low<high){ arr[high--] = arr[low]; } } arr[low] = pivot; System.out.println("low-->"+low); return low; } int QuickSort_K_MAX(int[] arr, int low, int high, int k) { if (low >= high) { return arr[low]; } int res=0; int mid = Sort(arr, low, high); //划分子递归数组 System.out.println("mid-->"+mid); if(mid==k){ res= arr[mid]; }else if (mid > k) { res=QuickSort_K_MAX(arr, low, mid - 1, k); //左递归 }else { res=QuickSort_K_MAX(arr, mid + 1, high, k); //右递归,一旦右递归mid+1=high,将退化成冒泡,递归深度将变成n,n为数组长度 } return res; } public int getK(int[] arr,int k){ return QuickSort_K_MAX(arr,0,arr.length-1,arr.length-k); } } //时间复杂度:接近O(N)
测试代码:
package com; import com.wj.MaxK; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * MaxK Tester. * Created by wangjia . * Date:09/05/2015 * Time:$Time * */ public class MaxKTest { private MaxK instance; @Before public void before() throws Exception { instance=new MaxK(); } @After public void after() throws Exception { instance=null; } @Test public void testGetK() throws Exception { int[] arr={4, 5, -1, 2, 3}; Assert.assertEquals(-1,instance.getK(arr, 5)); Assert.assertEquals(5,instance.getK(arr, 1)); Assert.assertEquals(4,instance.getK(arr, 2)); Assert.assertEquals(3,instance.getK(arr, 3)); Assert.assertEquals(2,instance.getK(arr, 4)); int[] arr2={-8,11,4,-2,44,56565,23,-232}; Assert.assertEquals(56565,instance.getK(arr2, 1)); Assert.assertEquals(44,instance.getK(arr2, 2)); Assert.assertEquals(-232,instance.getK(arr2, 8)); } }
解法6下次再来。
另外给出一些其他的参考文章:http://blog.csdn.net/beiyeqingteng/article/details/6992290
http://job.xdnice.com/content/BiShiJingYan/2012-11/3971.htm