1. 程式人生 > 實用技巧 >求第k小數

求第k小數

這篇文章包括題目思路程式碼時間複雜度分析幾部分。

題目:洛谷 求第k小的數

這裡的k可以取0,也就是有第0小的數(最小的數),所以,實際上相當於平常說的求第k+1小的數

想到了幾種做法,

首先,排序,輸出num[k];

其次,用一個輔助陣列儲存前(k+1)個最小的數,遍歷原陣列的時候更新輔助陣列,最後輸出這個輔助陣列中的最大值;

然後,還可以用快速排序的二分思想,將陣列分成小於基準的數、基準、大於基準的數共三部分,比較k和基準的序號,相等輸出基準值,小於遞迴基準左側的部分,大於遞迴基準右側的部分,相當於二分查詢和快速排序的結合。

下面是第二種和第三種的程式碼

//方法二
#include <stdio.h>
#define
MAXSIZE 5000000 long long num[MAXSIZE];//輔助陣列,儲存已遍歷的前k+1小的數 int main() { long long n, k,tmp; long long max = 0, max_node = 0, top = -1; scanf("%lld", &n); scanf("%lld", &k); for (long long i = 0; i < n; i++) { scanf("%lld", &tmp); if (top < k)//開始時,輔助陣列元素個數小於k+1,直接加入
{ num[++top] = tmp; if (max < tmp)//記錄好輔助陣列的最大值和最大值的序號 { max = tmp; max_node = top; } } else//當輔助陣列加入了k+1個元素之後 { if (max > tmp)//如果tmp小於輔助陣列當前的最大值 { max
= tmp; num[max_node] = tmp;//將最大值元素替換為tmp for (long long i = 0; i <= top; i++)//遍歷輔助陣列,重新選取最大值和最大值結點 if (max < num[i]) { max = num[i]; max_node = i; } } } } printf("%lld", max); return 0; }

//方法三
#include <stdio.h> #define MAXSIZE 5000000 long long num[MAXSIZE]; long long n, k; void sort(long long left, long long right) { if (left > right) return; long long greater = left, less = right, std = num[left]; while (greater < less) { while (less > greater&&num[less] >= std) less--; while (greater < less&&num[greater] <= std) greater++; if (greater != less) { long long tmp = num[less]; num[less] = num[greater]; num[greater] = tmp; } else { long long tmp = num[less]; num[less] = num[left]; num[left] = tmp; } } if (less == k)//原本的兩部分都要遞迴變成了只遞迴一部分 printf("%lld", num[less]); else if (less > k) sort(left, less - 1); else sort(less + 1, right); } int main() { scanf("%lld", &n); scanf("%lld", &k); for (long long i = 0; i < n; i++) scanf("%lld", &num[i]); sort(0, n - 1); return 0; }

時間複雜度分析

第一種,時間複雜度為O(n*log n),太大

第二種,時間複雜度為O(n~k*n),這種方法的最好和最壞的時間複雜度相差很大,最好的情況是原陣列升序排列,時間複雜度為n,最壞的情況是原陣列降序排列,時間複雜度為kn,當k≈n時,更是達到n2的級別

第三種,時間複雜度為Θ(n),寫出遞推方程T(n)=T(n/2)+O(n),利用主定理可以求解,而且最好和最壞時間複雜度都是Θ(n)

最後的結果是第一種60分,第二種0分、開 O2 40分,第三種100分(開O2更慢)

可能是測試樣例太刁鑽,導致第二種成績這麼差吧,唉~