早就听说快排改造能实现O(n)求第k小数,不过做到的题目基本上都可以快排/大根堆所以没研究过……
上周一位前辈提到淘宝的试题,貌似是在10W个不同数里面选出来最小的10个?渣渣第一反应就是快排T_T前辈说可以维护一个长度为10的链表,每次和其中最大的那个数比较替换就行,而且是O(n),我整个人就Orz了……
但是前辈也说如果挑出来最小的1W个就没办法了,只能用快排。我觉得维护一个尺寸为1W的大根堆稍快,然后又想到传说中的快速选择,如果选出来第1W小的数,循环输出所有小于等于它的就可以而且貌似还是O(n)?
正好回老家就YY了一个(这还用YY?)……
大体思路么,首先快排求k小是肯定没问题的;其次快排递归完的区间就能保证区间内数字在正确的位置上;再次我们只找一个数的排名,而这个数要么在[l,j]要么在[i,r]要么在(j,i),在(j,i)之间不进行递归显然已经排好了,不然直接递归一边就行。又考虑到既然只进行一边就是个很简单的尾递归了所以改成循环,然后就没有然后了……
粘代码……
int a[10000],n;
int qcho(int k) {
for (int l=1,r=n,i,j,x; l<r; k>=i?l=i:r=j) {
i=l,j=r,x=a[l+r>>1];
do {
while (a[i]<x) i++; while (a[j]>x) j--;
if (i<=j) {int y=a[i]; a[i++]=a[j]; a[j--]=y;}
} while (i<=j);
if (j<k&&k<i) return a[k];
}
return a[k];
}
不对啊,说好的10W怎么变成1W数组了?额,不要在意细节……