输出数组里面第N大的数
好像有些大公司出过面试题:找出数组里面第N大的数,当然有点变化,但本质部分是这样的.
要求是不能排序,时间复杂度不能超过O(n^2)
思路很多,我暂时就只会快排衍生的那种.如果对快速排序不太熟悉了,建议复习 我之前讨论的快速排序.
好的,现在假设你已经熟悉了快速排序.
每轮快排,我们都得找个支点,然后从数组的两边交替开始和支点比较,右边比支点小的数移到左边,左边比支点大的数移到右边,移到最后,只剩一个位置了,然后把支点填进来.这时,你发现在支点右边的数都比支点大.假设支点的index等于i,然后支点是第(endIndex-i+1)大的数了.(注意:endIndex是数组最后一个元素的下标)
记住我们的目标,我们的目标是要找第N大的数,如果endIndex -i + 1 = n,就说明我们找到了.但是2个数比较有3种结果.我们来分情况讨论下:
记th = endIndex - i + 1,find(a, startIndex, endIndex, n)
(1) th = n,返回支点
(2) th > n,说明第n大的数在支点右边,所以在右边继续找:find(a, i + 1, endIndex, n)
(3) th < n,说明第n大的数在支点左边,右边的数都比要找的数大,也比支点大,所以只需要在左边找第(n - th)大的数即可,find(a, startIndex, i - 1, n - th)
代码:
#include<stdio.h> #include<stdlib.h> int choose_nth(int a[],int startIndex, int endIndex, int n); int main(int argc, char *argv) { int a[] = {150,111,1000,99,300,10,189}; int n,i; int an = sizeof(a)/sizeof(int); printf("数组:\n"); for(i = 0 ; i < an; ++i) printf("%d ",a[i]); printf("\n"); printf("想找第几大的数:"); scanf("%d",&n); int ans = choose_nth(a, 0, an - 1, n); printf("第%d大的数是:%d\n", n, ans); return 0; } int choose_nth(int a[], int startIndex, int endIndex, int n) { int midOne = a[startIndex]; int i = startIndex, j = endIndex; if(i == j) //递归出口之一 return a[i]; if(i < j) { while(i < j) { for(; i < j; j--) if(a[j] < midOne) { a[i++] = a[j]; break; } for(; i < j; i++) if(a[i] > midOne) { a[j--] = a[i]; break; } } a[i] = midOne;//支点归位 int th = endIndex - i + 1;//计算下标为i的数第几大 if(th == n)//正好找到 { return a[i]; } else { if(th > n )//在支点右边找 return choose_nth(a, i + 1, endIndex, n); else//在支点左边找第(n-th)大,因为右边th个数都比支点大 return choose_nth(a, startIndex, i - 1, n - th); } } }
输出结果:
数组: 150 111 1000 99 300 10 189 想找第几大的数:4 第4大的数是:150