找出乙個有10億數字陣列中,前k個最大值
第一步:hash去重
解法1:劃分法
def partition(l, left, right):
low = left
if left < right:
key = l[left]
high = right
while low < high:
while low < high and l[high] <= key:
high -= 1
l[low] = l[high]
while low < high and l[low] >= key:
low += 1
l[high] = l[low]
l[low] = key
return low
def topk(l, k):
if len(l) < k:
pass
low = 0
high = len(l) - 1
j = partition(l, low, high)
while j != k and low < high:
if k > j:
low += 1
else:
high = j
j = partition(l, low, high)
if __name__ == "__main__":
l = [3,2,7,4,6,5,1,8,0, 19, 23, 4, 5, 23, 3, 4, 0,1,2,3,45,6,5,34,212,3234,234,3,4,4,3,43,43,343,34,34,343,43,2]
n = 2 #find most max value
topk(l, n)
print 'result:', l[0:n]
result: [3234, 343]
思路:利用快速排序的原理,每次選取第left的值作為參考值:找出乙個劃分位置low,使得l[low],左邊的值比參考值大,右邊的值比參考值小,這樣一直持續下去,直到low和k相等,則可以找到前k個最大值。因為選取每個參考值,都要便利一遍陣列,因此:演算法複雜度為o(n)。
優點:演算法複雜度最低
解法2:大頂堆法
思路:先用前k個值構建大頂堆,也就是頂部是最大值,如果下乙個值比頂部大,則立馬調整這個大頂堆,否則取葉子節點肯定是乙個最小值,如果陣列中值比最小值還小,則直接捨棄。 演算法複雜度為o(n * log(n))
堆排序基本實現:
#coding: utf-8
#!/usr/bin/python
# create heap
def build_heap(lists, size):
for i in range(0, (int(size/2)))[::-1]:
adjust_heap(lists, i, size)
# adjust heap
def adjust_heap(lists, i, size):
lchild = 2 * i + 1
rchild = 2 * i + 2
max = i
if i < size / 2:
if lchild < size and lists[lchild] > lists[max]:
max = lchild
if rchild < size and lists[rchild] > lists[max]:
max = rchild
if max != i:
lists[max], lists[i] = lists[i], lists[max]
adjust_heap(lists, max, size)
# heap sort
def heap_sort(lists):
size = len(lists)
build_heap(lists, size)
for i in range(0, size)[::-1]:
lists[0], lists[i] = lists[i], lists[0]
adjust_heap(lists, 0, i)
return lists
a = [2,3,4,5,6,7,8,9,1,2,34,5,4,54,5,45,4,5,45,4,5,646,456,45,6,45,645,6,45,6,456,45,6,323,412,3,25,5,7,68,6,78,678]
print("began sort:%s" %a)
b = heap_sort(a)
print("end sort:%s" %b)
began sort:[2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 34, 5, 4, 54, 5, 45, 4, 5, 45, 4, 5, 646, 456, 45, 6, 45, 645, 6, 45, 6, 456, 45, 6, 323, 412, 3, 25, 5, 7, 68, 6, 78, 678]
end sort:[1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 25, 34, 45, 45, 45, 45, 45, 45, 54, 68, 78, 323, 412, 456, 456, 645, 646, 678]
堆排序 TOPK問題 C
現在有n個數,設計演算法得到前k大的數。k 首先從原列表擷取前k個元素,組成乙個新列表。然後將這個新列表構建成乙個小根堆,那麼根就新列表中最小的數。接著繼續從原列表取出k以後的元素,和小根堆根比對,如果比根小,那麼肯定不屬於前k大的數,如果比根大,替換根,然後做一次向下調整,根重新變成新列表最小的數...
面經筆記 堆排序與topk問題
維持堆函式 h為新元素位置,假設h的兩個孩子樹已經是最大堆 1 如果d h 為d h 左孩子 右孩子中的最大值,則結束調整。2 否則,將x h 與孩子中的最大值互換,更新h值,返回上一步 void keepheap int array,int len,int h if rightchild len ...
堆排序的應用 TOPK問題
我們知道堆有大根堆和小根堆兩種,那麼在解決找堆中k個最大值的問題時應該用大根堆還是小根堆呢?答案是找k個最大的,要建立k大小的小堆。思路如下 比如下面這個陣列,要去取出其中最大的四個值,然後將後面的值與堆頂值比較,若大於堆頂值則彈出堆頂,將新的值加入堆 重複這個步驟,堆中的值會整體增大,陣列遍歷完後...