日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

查找N个数中第K大的数

發布時間:2024/7/23 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 查找N个数中第K大的数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
方法一:將一組數放入數組中,升排序。并返回第 ( length - k )個元素
這里消耗的時間就是排序用的時間,用快速排序則為:O( N log N )


代碼:

/*** 先排序后獲取* @return** Date :2012-7-4* Author :GongQiang*/public int sortThenGet( int k ){Collections.sort( list );return list.get( list.size() - k );}

方法二:構造一個 K 長度的數組,將前K位數復制過來并排序(降序)。然后依次將 K+1 到 N 位的數比較并插入 K 長度的數組中。返回最后一個即可。

這時間度為:O( N*K ) 如果 K = N/2 ?則復雜度為 O( N*N )


代碼:

/*** 先取出前K個數排序,再從后面依次插入* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int kSortThenCompare( int k ){List<Integer> result = new ArrayList<Integer>( k );for( int i=0 ; i<k ; i++ ){result.add( list.get(i) );}//前K位數,按照從大到小排序Collections.sort( result, new Comparator<Integer>(){public int compare(Integer o1, Integer o2) {if( o1 > o2 ){return -1;}if( o1< o2 ){return 1;}return 0;}});// 后 K+1 位數與前面的有序數組比較,插入適當的位置for( int i=k ; i<list.size() ; i++ ){int j = k-1;while( j>=0 && list.get(i) > result.get(j) ){j--;}if( 0<=j && j<k-1 && list.get(i) < result.get(j) ){result.add( j+1, list.get(i) );}else if( j==-1 ){ //結束條件是 j==-1result.add( 0, list.get(i) );}}return result.get( k-1 );}

方法三:將 N 個數構造成一個“大堆”,然后刪除堆的根 K 次,最后一次即為結果。

?構造堆的最壞用時:O( N )

每次刪除根用時:O( log N )

則中的運行時間為: O( N + k*log N )

如果 K = O( ?N/ log N ) ,則總共用時就是構造堆的時間,即 O( N )

如果 K 很大,則總時間為 O( K* log N)

如果 K = N/2,則總時間為Θ( N*log N )


代碼:

/*** 先構建一個堆,然后獲取* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int buildHeapThenGet( int k ){PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( NUMBER_COUNT, new Comparator<Integer>(){ //這里是取第K大的元素,因而要改變排序規則public int compare(Integer o1, Integer o2) {if( o1 > o2 ){return -1;}if( o1< o2 ){return 1;}return 0;}});for( int i=0 ; i<list.size() ; i++ ){heapQueue.add( list.get(i) );}int result=0;for( int i=0 ; i<k ; i++ ){result = heapQueue.remove();}return result;}

方法四:思路和方法二一樣,只不過用堆來實現。

構造堆的時間:O( K )

處理每個其余元素的時間:O( 1 )

檢測是否進入堆的時間:O( log K )

總時間:O( K + (N-K)*log K ) = O( N* log K )

該算法找出中位數的時間界面:Θ( N*log N )

注意:這里使用優先隊列提供的堆來操作,這樣

檢測的時間為O( log K )

刪除的時間為O( log K )

插入的時間為O( log K )

所以,這里的代碼時間復雜度比單純在堆上操作要多很多。


代碼:

/*** 前K個數構造一個堆,然后進行比較插入* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int heapOfFistKThenSert( int k ){PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( k );for( int i=0 ; i<k ; i++ ){heapQueue.add( list.get(i) );}for( int j = k ; j<list.size() ; j++ ){int queueLength = k;int flag = 0;while( queueLength >0 ){if( heapQueue.peek() < list.get(j) ){flag =1;break;}queueLength--;}if( flag == 1 ){heapQueue.poll();heapQueue.offer( list.get(j) );}}return heapQueue.peek();}
四種算法在 10 萬個數值中,查找第100大,1000大,10000大實際用時

先排序在獲取: 用時間:69547064, 100大數:99903985 用時間:64447309, 1000大數:98963233 用時間:63601693, 10000大數:89862625先排序前K個數,然后插入,最后獲取: 用時間:14299865, 100大數:99903985 用時間:94025432, 1000大數:98963233 用時間:4053122244, 10000大數:89857698先構建一個堆,然后獲取: 用時間:29191262, 100大數:99903985 用時間:11743673, 1000大數:98963233 用時間:21491442, 10000大數:89862625先構建一個堆(前K個數),依次比較插入,最后獲取: 用時間:199040953, 100大數:99903985 用時間:1786736869, 1000大數:98963233 用時間:11739682175, 10000大數:89862625
可以看出,方法三最優。

方法五:隨機選擇(參考快速排序的思想)

/*** 隨機選擇* @param list* @param start* @param end* @param i* @return** Date :2012-10-25* Author :GongQiang*/int randomSelect( List<Integer> list, int start, int end, int i ){if( start == end ){return list.get(start);}int q = randomPartition(list, start, end);int k = end - q + 1;if( i == k ){return list.get( q );}else if( i<k ){return randomSelect(list, q+1, end, i);}else{return randomSelect(list, start, q-1, i-k);}}private int randomPartition( List<Integer> list, int start, int end ){int i = (int)(random.nextFloat()*( end-start )) + start;swap( list, i, end );return partition(list, start, end);}private int partition( List<Integer> list, int start, int end ){int temp = list.get(end);int i = start - 1;for( int j=start; j<end; j++ ){if( list.get(j) <= temp ){i++;swap( list, i, j);}}swap( list, i+1, end);return i+1;}private void swap( List<Integer> list, int i, int j ){int temp = list.get(i);list.set(i, list.get(j));list.set(j, temp);}

運行性能比較(一百萬中查詢):

先排序在獲取: 用時間:1073446509, 100大數:99991468 用時間:1086298487, 1000大數:99897550 用時間:995448554, 10000大數:98988059 用時間:996302124, 550000大數:45011888先構建一個堆,然后獲取: 用時間:98659237, 100大數:99991468 用時間:92088339, 1000大數:99897550 用時間:114273553, 10000大數:98988059 用時間:1590825451, 550000大數:45011888隨機選擇 用時間:113330378, 100大數:99991468 用時間:121606562, 1000大數:99897550 用時間:123834509, 10000大數:98988059 用時間:231643029, 550000大數:45011888

可以看出,【隨機選擇】性能很穩定,而且較優!

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的查找N个数中第K大的数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。