好像有些大公司出過面試題:找出數組里面第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