題目描述:查詢最小的k個元素
題目:輸入n個整數,輸出其中最小的k個。
例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為1,2,3和4。
我的解題思路:
1.最容易想到的思路
對於本題,最容易想到的思路就是先進行一次排序(如快速排序),排完序之後,直接取前k個數即可。時間複雜度為o(n*logn+k)=o(n*logn)。接下來就是要思考可以優化的地方。使用排序演算法是把所有n個數都進行了排序,但是實際上有n-k個數是不需要進行排序的,而且k個最小的數之間的排序也是不需要的。這些就是可以優化的地方。對源問題換一種表述方式就轉換為這樣的問題,在n個數中尋找k個數,使得k個數中的最大值小於其餘n-k數的任乙個。這樣就容易想到思路2.
2.先取最先的k個數,假設這k個數就是我們要找的k個數。(這也是一種思維方式,我們要找k個最小的數,但是沒有太好的辦法知道k個數中第乙個數是哪個,第二個數是哪個,那只能摸著石頭過河,就假定最先遍歷到的k個數為最小的k個數,然後再進行後續的彌補)然後遍歷其餘的n-k個數,對於遍歷得到的每個數,都要比較其和k個數中最大數的關係,然後再進行相應的操作。如果僅僅使用陣列的資料結構,那麼每次都要從k個數中遍歷尋找最大的數,這也是可以優化的地方,然後就可以想到利用最大堆的資料結構。
3.思路2的改進–利用最大堆的資料結構
最大堆資料結構的實現程式:
#include
using
namespace
std;
template
void max_heap(t * src,int idx,int num);
template
void swap(t * a,t * b );
/*對大小為num陣列src,節點idx的左右子樹均滿足最大堆的性質,現在將整個樹調整為最大堆*/
/*就地操作*/
template
void max_heap(t * src,int idx,int num)
if((righttmp_max))
if(tmp_idx!=idx)
}template
void swap(t * a,t * b )
void main()
; int num = sizeof(src)/sizeof(int);
int st_idx =num/2 -1;
for(int i=st_idx;i>=0;i--)
max_heap(src,i,num);
for(int i=0;icout
<< src[i] << endl;
}}
利用最大堆的資料結構,先取前k個數,建立最大堆,耗時為o(k)。接下來遍歷後n-k個數,每個數都與前k個數的最大值進行比較。因為最大堆的插入刪除等操作的複雜度均為o(log k),比陣列要快,因此最後整個程式的時間複雜度為o(k+(n-k)*logk)=o(n*logk)。
注:對最大堆資料結構的思考:為什麼採用最大堆的資料結構可以優化時間效率?需要付出何種代價?對我們有何啟示?
最大堆之所以提高時間效率,從根本上說還是減少了重複遍歷陣列的次數,第一次需要完整的遍歷整個陣列,然後建立最大堆。之後的遍歷就可以利用之前最大堆的性質,從而不必遍歷陣列的所有元素,因而可以改進時間效率。付出的代價是需要維護最大堆的資料結構,陣列元素的新增和刪除都要進行額外的操作。對我們的啟示是:為了降低時間複雜度,應當根據題目要求建立合適的資料結構以充分上一次完整遍歷的結果,減少總共的遍歷次數。
程式設計師程式設計藝術總結
第一章 左旋轉字串 第二章 字串是否包含及匹配 查詢 轉換 拷貝問題 第三章 尋找最小的k個數 第三章續 top k演算法問題的實現 第三章再續 快速選擇select演算法的深入分析與實現 第三章三續 求陣列中給定下標區間內的第k小 大 元素 第四章 現場編寫類似strstr strcpy strp...
程式設計師程式設計藝術 回文判斷
鳴謝 感謝 july,您的部落格給予我很大的幫助,增強了我學習的動力。希望分享的力量永傳!本文問題源於 july的文章,修正了 july關於回文 的bug,現將本人 發布如下 如發現有問題,還希望不吝賜教。謝謝。include include using namespace std int max ...
程式設計師交流的藝術
程式設計師除了給人一種髮際線偏高的感覺外,很悶很宅很難溝通應該也是丟給大家的印象之一!但往往有效的溝通又是程式設計師所必備的一項技能,因為掌握說話的方式技巧,可以有效避免一些無謂的爭端,甚至是暴力血腥的場面發生!例如程式設計師與產品經理的溝通!如果你是乙個很難用語言準確的將內心想法表達出來的程式設計...