今天和大家一塊學習下面試中常見的兩個關於堆的面試題,第一:求k個最大值;第二:求中值元素。演算法和資料結構算是筆者的死穴了。
一、求前k個最大的值
首先能想到的是使用arrays.sort()進行排序後取前k個值即可,效率是o(n*log2^n)。前方高能**其次可以進行迴圈選擇k次,每次都從剩下的資料中選擇最大值,效率是o(n*k)。但若k值大於log2^(n),其效率還不如完全排序。
況且上述方法並沒有考慮到資料的動態性,當資料是動態新增的情況下,如何維護前k個值呢?
此時,維護乙個長度為k的陣列,陣列中的k個位置填充我們需要的前k個數值,面對源源不斷的資料,都先找到陣列中的最小值,將新來的資料和最小值進行比較,若是大於最小值,則將最小值替換成新數值。那麼問題來了,每來乙個數值都需找到陣列中的最小值進行k次比較,會不會略顯繁瑣呢?
上述方法也僅僅是青銅,真正的王者上場了。解決方法是用最小堆互為這k個數值。最小堆,顧名思義,根節點永遠是最小的數值,那麼新來的元素僅需和根節點進行比較即可:小於根節點則pass,否則新值取代根節點,並且向下調整堆,調整的效率為o(log2^k),這樣總體的效率是o(n*log2^k),是不是比上面的方法高效了很多了呢?
talk is cheap,so codes follow.
class topk
/*** 新增集合中的所有元素.
*/public
void
addall(collection<? extends e> c)
} public
void
add(e e)
comparable<? super e> heap = (comparable<? super e>) p.peek();
//新來的小於根節點,不做什麼東西
if (heap.compareto(e) > 0)
// 新來的大於根節點,把根節點拋棄,加入新來的數值
p.poll();
p.add(e);
} public
t toarray(t a)
/*** 返回第k大的值.
*/public e getkth()
}/**
* created by mollychin on 2018/5/28.
*/public
class
topktest );
top5.addall(integers);
system.out.println("保留5個最大的元素,輸出為:");
system.out.println(arrays.tostring(top5.toarray(new integer[0])));
system.out.println(top5.getkth());
}}
輸出結果為:
保留5個最大的元素,輸出為:
[87, 99, 88, 100, 554]
87
二、求中值
乙個簡單的思路是排序後取中間的那個值即可,效率是o(n*log2^n)。假設中值是z,則最大堆維護的是小於等於z的數值,最小堆維護的是大於等於z的數值。但是呢,兩個堆都不包含m。但上述方法僅適用於全部數值已知,那麼面對動態新增的數值呢?
可以使用兩個堆,最大堆和最小堆。下面是思路:
當有新的數值n到達的時候,n與z進行比較,按照步驟一的約定將n加入最大堆或者最小堆中。
走完第二步後,若最小堆和最大堆的元素個數相差2個或者2個以上,則將m加入元素較少的堆中,然後從元素較多的堆中的根節點移除並且賦值給z。
4.下面我們來看下**實現。
/**
* created by mollychin on 2018/5/28.
*/public
class
mediantest );
integermedian.addall(integers);
system.out.println("中位數是:"+integermedian.getm());
}}class median
private
intcompare(e e, e m)
public
void
add(e e)
if (compare(e, m) <= 0) else
if (minheap.size() - maxheap.size() >= 2) else
if (maxheap.size() - minheap.size() >= 2)
} public
void
addall(collection<? extends e> c)
} public e getm()
}
中位數是:45
總結
相比較排序,使用堆的效率可以大大提高,而且還可以應對資料源源不斷到來的情景,可以給出實時滿意的結果。這大概就是演算法和資料結構的藝術吧(逃
利用堆求最大或最小的前k個數
用堆在海量資料中找出最大或最小的k個數,效率非常高。1 在一組資料中找出最小的k個數 解題思路 要找出最小的k個數,我們可以先用這組資料中的k個數構建一棵 最大堆 然後再將剩下的元素與堆頂元素相比。如果大於堆頂元素,則不做處理,繼續向下比較。如果小於堆頂元素,則將堆頂元素與這個元素交換,然後再恢復堆...
動態求前n個最小值 最大值
注 由於最小值和最大值的分析過程完全相同,這裡我們只討論最小值的分析流程,最大值同理 每次給定乙個數值,詢問此數值以及之前給定數值中最小的n個數 例如給定數值的順序為 8 7 1 2 9 4,設n 3 乙個最直觀的方法是,每次新增新的資料後,將當前所有資料進行排序,選擇較小的n個 一次排序最快也要 ...
利用K 堆求最大的K個數
1.原理 1.1將資料存在陣列中,利用堆排排序陣列的前k個數 遞增 此時建立的是小堆,陣列的第乙個元素儲存堆中最小值。1.2從 k 1 個陣列元素遍歷到最後,每次都和堆頂元素對比,如果大於堆頂元素,交換兩者,調整堆。1.3輸出陣列前k個數,就是最大的k個數。include define k 3 vo...