乱序不重复整数数组求中位数
2015-11-03 17:29
459 查看
今天去面试遇到一道算法题,40亿整数乱序不重复的情况下,如何取它的中位数,要求时间复杂度为O(n)。
首先想到的是快排加二分查找的思想,取一个数进行partition之后确定它的绝对位置,就可以放弃少的一边的比较。
搜了一下发现有个QuickSelect算法,也一起放进来对比了。
最后仔细看了一下,QuickSelect算法其实就是快排加二分。。。一样的思路。
最后还有一种是用数组的,不过如果能用bitmap可以省下很多内存。同学说时间复杂度也是O(n),但是可能因为语言的关系,往数组存1花了很多时间。代码贴一下吧:
结果是快排加二分的速度跟QuickSelect的速度基本是一样的。不知道有没有更快的方法?
参考
- http://codepad.org/pQsNnpqd
- http://blog.csdn.net/morewindows/article/details/6684558
首先想到的是快排加二分查找的思想,取一个数进行partition之后确定它的绝对位置,就可以放弃少的一边的比较。
搜了一下发现有个QuickSelect算法,也一起放进来对比了。
最后仔细看了一下,QuickSelect算法其实就是快排加二分。。。一样的思路。
最后还有一种是用数组的,不过如果能用bitmap可以省下很多内存。同学说时间复杂度也是O(n),但是可能因为语言的关系,往数组存1花了很多时间。代码贴一下吧:
package cn.springmvc.test; import java.util.Arrays; import java.util.HashSet; public class UserTest { /** * @param args */ public static void main(String args[]) { HashSet<Integer> hashSet = new HashSet<Integer>(); int maxSize = 4000000; int random = 10000000; while(hashSet.size()<maxSize){ int x=(int)(Math.random() * random); hashSet.add(x); } int[] arr = new int[maxSize]; int[] arr2 = new int[maxSize]; int[] arr3 = new int[maxSize]; int[] arr4 = new int[maxSize]; int max = 0; Integer[] a =hashSet.toArray(new Integer[0]); int aLength = a.length; for(int i=0;i<aLength;i++){ arr[i]=a[i]; arr2[i]=a[i]; arr3[i]=a[i]; arr4[i]=a[i]; } //数组算法 long before0 = System.currentTimeMillis(); for(int i=0;i<aLength;i++){ if(max<a[i])max = a[i]; } int[] arr5 = new int[max+1]; for(int i=0;i<aLength;i++){ arr5[a[i]]=1; } int counter = 0; int ii=0; for(int i=0;i<arr5.length;i++){ counter = counter + arr5[i]; ii=i; if(counter==aLength/2)break; } System.out.println(System.currentTimeMillis()-before0); System.out.println(ii); //QuickSelect long before = System.currentTimeMillis(); int rs = quick_select(arr,maxSize); System.out.println(System.currentTimeMillis()-before); System.out.println(rs); //快排加二分 long before3 = System.currentTimeMillis(); quick_sort1(arr3,0,maxSize-1,(maxSize-1)/2); System.out.println(System.currentTimeMillis()-before3); System.out.println(arr3[(maxSize-1)/2]); //Arrays快排 long before2 = System.currentTimeMillis(); Arrays.sort(arr2); System.out.println(System.currentTimeMillis()-before2); System.out.println(arr2[maxSize/2-1]); //普通快排 long before4 = System.currentTimeMillis(); quick_sort(arr4,0,maxSize-1); System.out.println(System.currentTimeMillis()-before4); System.out.println(arr4[(maxSize-1)/2]); } public static int quick_select(int[] arr,int n){ int low, high; int median; int middle, ll, hh; low = 0 ; high = n-1 ; median = (low + high) / 2; for (;;) { if (high <= low) /* One element only */ return arr[median]; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr, low,high) ; return arr[median] ; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr, middle,high) ; if (arr[low] > arr[high]) ELEM_SWAP(arr, low,high) ; if (arr[middle] > arr[low]) ELEM_SWAP(arr,middle, low) ; /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr,middle, low+1) ; /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]) ; do hh--; while (arr[hh] > arr[low]) ; if (hh < ll) break; ELEM_SWAP(arr,ll, hh) ; } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr,low, hh) ; /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } public static void ELEM_SWAP(int[] arr,int a, int b){ int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } static int AdjustArray(int s[], int l, int r) //返回调整后基准数的位置 { int i = l, j = r; int x = s[l]; //s[l]即s[i]就是第一个坑 while (i < j) { // 从右向左找小于x的数来填s[i] while(i < j && 9910 s[j] >= x) j--; if(i < j) { s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑 i++; } // 从左向右找大于或等于x的数来填s[j] while(i < j && s[i] < x) i++; if(i < j) { s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑 j--; } } //退出时,i等于j。将x填到这个坑中。 s[i] = x; return i; } static void quick_sort1(int s[], int l, int r,int middle) { if (l < r) { int i = AdjustArray(s, l, r);//先成挖坑填数法调整s[] if(i>middle){ quick_sort1(s, l, i - 1,middle); // 递归调用 }else if(i<middle){ quick_sort1(s, i + 1, r,middle); }else return; } } static void quick_sort(int s[], int l, int r) { if (l < r) { //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1 int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j] >= x) // 从右向左找第一个小于x的数 j--; if(i < j) s[i++] = s[j]; while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 i++; if(i < j) s[j--] = s[i]; } s[i] = x; quick_sort(s, l, i - 1); // 递归调用 quick_sort(s, i + 1, r); } } }
结果是快排加二分的速度跟QuickSelect的速度基本是一样的。不知道有没有更快的方法?
参考
- http://codepad.org/pQsNnpqd
- http://blog.csdn.net/morewindows/article/details/6684558
相关文章推荐
- 只有程序员看的懂的面试圣经|如何拿下编程面试
- 下一次技术面试时要问的 3 个重要问题
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- PHP程序员面试 切忌急功近利(更需要注重以后的发展)
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析