面试问题1:给一个无序数组,找到其中位数。
博主内推:阿里菜鸟网络春招 【部门直推】【海量实习岗位&正式岗位】
问题描述:给一个无序数组,找到其中位数,并说出该算法的时间复杂度以及空间复杂度。
解题方法一:
中位数:当数组元素个数为奇数n时,中位数=a[n/2]。当元素个数为偶数时,中位数=( a[n / 2] + a[ ( n + 1 ) / 2 ])
按照这个中位数定义来求解。利用快速排序对数组进行排序,时间复杂度为O(nlogn) 空间复杂度为S(1); 之后的找到中位数所用时间复杂度为O(1) 空间复杂度为O(1)
解题方法二:
在了解方法二之前我们先来了解一下快速排序。对于快排算法,其中主元的选择对于数组的划分起到很大的影响,从而对于运行时间产生很大的影响。当主元不能很好地分割数组,即主元将数组分成一个子数组中有一个记录,而另一个子组组有 n -1 个记录时,下一次的子数组只比原来数组小 1,这是快速排序的最差的情况。如果这种情况发生在每次划分过程中,那么快速排序就退化成了冒泡排序,其时间复杂度为O(n2)。老师曾经举过一个例子:甲、乙两同学去比较各自排序算法的好坏,他们可以互相阅读对方的原代码,然后互相给对方提供无序数组,最后比较那个运行比较快。乙同学看到甲同学的快排的代码,乙同学针对甲同学的代码专门写了所谓的无序数组(并非无序数组,只是甲同学的代码在解决这个无序数组的排序中会退化成冒泡排序)。然而甲同学看到乙同学的快排代码之后就老老实实的给了无序数组。为什么甲同学没有去找针对于乙同学的那个能够导致退化的无序数组呢?原因就是乙同学的快排主元的选择是随机化的。
随机化排序代码:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int partition(int *a,int p,int r); 4 int random_partition(int *a,int p,int r); 5 int random_select(int *a,int p,int r,int i); 6 int main() 7 { 8 9 system("pasue"); 10 return 0; 11 } 12 int partition(int *a,int p,int r) 13 { 14 int x=a[r],t; 15 int i=p-1,j; 16 for(j=p;j<=r-1;j++) 17 { 18 if(a[j]<=x)//如果要降序排列,则改为if(a[j]>=x) 19 { 20 i++; 21 t=a[i]; 22 a[i]=a[j]; 23 a[j]=t; 24 } 25 } 26 t=a[i+1]; 27 a[i+1]=a[r]; 28 a[r]=t; 29 return i+1; 30 } 31 int random_partition(int *a,int p,int r) 32 { 33 int t,i; 34 i=p+(int)((r-p+1)*rand()/(RAND_MAX+1.0));//利用随机数随机选择用于分割的元素,注意范围 35 t=a[i]; 36 a[i]=a[r]; 37 a[r]=t; 38 return partition(a,p,r); 39 } 40 int random_select(int *a,int p,int r,int i)//找出a[p]——a[r]之间第i小的元素 41 { 42 int q; 43 if(p==r) 44 return a[p]; 45 q=random_partition(a,p,r); 46 int k=q-p+1; 47 if(i==k) 48 return a[q]; 49 else if(i<k) 50 return random_select(a,p,q-1,i); 51 else 52 return random_select(a,q+1,r,i-k); 53 }
线性时间选择算法:
含义:是解决选择问题的分治算法
与快速排序不同的是:快排递归处理划分的两边,而线性选择只对其中
的一个部分进行处理
时间复杂度:O(n)
实现:需要用到随机划分函数
主要的过程好似:A[p...r]通过随机划分函数得到枢轴q
根据划分的两个区间A[p...q-1],A[q],A[q+1...r]
然后判断<=A[q]的元素数量k=q-p+1 与 需要寻找的第i小的关系
如果 k == i,直接返回A[q]
如果 k > i,说明第i小的元素只可能在区间A[p...q-1]中
如果 k < i ,说明第i小的元素在区间A[q+1...r]中 ,并且问题转化为在A[q+1...r]中寻找第i-k小的元素
参考代码:
1 #include <iostream> 2 #include <stdlib.h> 3 #include <stdlib.h> 4 5 using namespace std; 6 7 //返回iMin~iMax中的任意数字 8 int myrandom(int iMin,int iMax) 9 { 10 // 3~6,6-3=3 , 11 int iResult = rand() % (iMax - iMin + 1) + iMin; 12 return iResult; 13 } 14 15 void swap(int* pArr , int p , int q) 16 { 17 int iTemp = pArr[p]; 18 pArr[p] = pArr[q]; 19 pArr[q] = iTemp; 20 } 21 22 int randomPartition(int* pArr,int iLow ,int iHigh) 23 { 24 int iRand = myrandom(iLow , iHigh); 25 swap(pArr , iRand , iLow); 26 int iPivot = pArr[iLow]; 27 //下面就是快排的枢轴划分 28 while(iLow < iHigh) 29 { 30 while(iLow < iHigh && pArr[iHigh] >= iPivot) 31 { 32 iHigh--; 33 } 34 pArr[iLow] = pArr[iHigh]; 35 while(iLow < iHigh && pArr[iLow] <= iPivot) 36 { 37 iLow++; 38 } 39 pArr[iHigh] = pArr[iLow]; 40 } 41 pArr[iLow] = iPivot; 42 return iLow; 43 } 44 45 int randomizedSelect(int* pArr,int p ,int r,int i) 46 { 47 if(p == r) 48 { 49 return pArr[p]; 50 } 51 int q = randomPartition(pArr, p ,r); 52 int k = q - p + 1; 53 if(i == k) 54 { 55 return pArr[q]; 56 } 57 //在低区间 58 else if(i < k) 59 { 60 int iResult = randomizedSelect(pArr, p , q-1 ,i); 61 return iResult; 62 } 63 else 64 { 65 int iResult = randomizedSelect(pArr , q + 1 , r , i - k); 66 return iResult; 67 } 68 } 69 70 void process() 71 { 72 int n,u; 73 while(cin >> n >> u) 74 { 75 int* pArr = new int[n]; 76 for(int i = 0; i < n ; i++) 77 { 78 cin >> pArr[i]; 79 } 80 int iResult = randomizedSelect(pArr, 0 , n -1 , u); 81 cout << iResult << endl; 82 delete[] pArr; 83 } 84 } 85 86 int main(int argc,char* argv[]) 87 { 88 process(); 89 getchar(); 90 return 0; 91 }
作者: 伊甸一点
出处: http://www.cnblogs.com/zpfbuaa/
本文版权归作者伊甸一点所有,欢迎转载和商用(须保留此段声明),且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文链接 如有问题, 可邮件(zpflyfe@163.com)咨询.