**出處
題目:給出n個無序的數,然後找出其中最大的k個數
解題思路:
首先測試資料有可能會有一億個數,資料量特別的大,資料庫不可能儲存這麼多的資料。如果直接sort排序,nlogn時間複雜度實在是太高,大於10^9。我們可以考慮對資料進行分塊讀取,每次讀取的資料塊大小應大於k。
不如先假設第一次讀取的資料塊前k個數最大,然後把k個數建成最小二叉堆。然後從第k+1個數開始,每個數都與堆頂的數值進行比較,如果數字i大於堆頂則把堆頂的元素的元素替換成i,再調整一次堆。最後讀取完資料之後,這個二叉堆裡面的元素就是從小到大排序好的最大k個數。
時間複雜度:
o(nlogk)
空間複雜度:
o(k)
證明過程:
為什麼求最大的k個用的不是最大堆,而是最小堆?最大堆堆頂的元素是最大的,往下的子樹越來越小,把n個數建成最大堆,那麼堆頂往下的k個數就是最大的k個數。但是時間複雜度o(nlogn)和空間複雜度o(n)太高!
排序時間複雜度很高,是因為進行了很多沒有用的判斷,我們只需要取最大的k個數,而排序則把n個數都從小到大排序好了。建立乙個k個數的最小堆,假設堆裡面的元素是最大的,當然只是假設。如果從m+1到n這些數只要有數大於最小堆堆頂的數,那麼假設就不成立,堆頂那個數就不符合,自然把它去掉,把新的數加進來,再重新調整堆,使得堆頂的元素最小。
為什麼要用最小堆呢?因為每次查詢這k個數裡面的最小的那個數就是堆頂,時間複雜度是o(1)。如果直接用陣列來儲存這k個數,雖然查詢的時間複雜度是logn,但是當把這個數插入陣列的時候,陣列比它小其他元素還需要往前平移,所以時間複雜度遠遠大於logn。由於每次調整堆的時間複雜度是logn。所以最小堆的做法的時間複雜度是
o(nlogk),而空間複雜度只有o(k)。
**1 c++的
stl庫優先佇列實現二叉堆:
[html]view plain
copy
#include
<
stdio.h
>
#include <
stdlib.h
>
#include <
string.h
>
#include <
algorithm
>
#include <
queue
>
using namespace std;
struct cmp
};
#define max 11000
int a[max];
using namespace std;
priority_queue<
int,vector
<
int>
,cmp
>
q;
int main()
else
}
} k=
0;
while(!q.empty()) //這樣處理是為了最後乙個數列印時沒有空格
for(i=0
;i<
k;i++)
return 0;
}
**2 (陣列實現堆):
[html]view plain
copy
#include
<
stdio.h
>
#define max 10001
int a[max];
void heapadjust(int r,int s,int t) //篩選函式1
r[i]=temp;
}
void heapsort(int r,int n) //堆排
for(i=n
;i>
1;i--)
}
void heapadjust2(int r,int s,int t) //篩選函式2
r[i]=temp;
}
int main()
heapsort(a,m);
for(i=m
+1;i
<
=n;i++)
}
heapsort(a,m);
for(i=1
;i<
=m;i++)
return 0;
}
N個數中找出最大的K個數
題目描述 有很多個 n個 無序的數,我們姑且假定它們各不相等,怎麼選出其中最大的若干個 k個 數呢?1.n 100,k 10的時候怎麼處理?2.n 1000,k 100呢?3.n 1億億個,k 100呢?如果這些數是整數的話,怎麼處理?如果是浮點數呢?如果這些數是整數,並且存在上界呢?如果將題目中的...
找出N個整數中最大的K個數
所謂 第 前 k大數問題 指的是在長度為n n k 的亂序陣列中s找出從大到小順序的第 前 k個數的問題。解法1 我們可以對這個亂序陣列按照從大到小先行排序,然後取出前k大,總的時間複雜度為o n logn k 解法2 利用選擇排序或互動排序,k次選擇後即可得到第k大的數。總的時間複雜度為o n k...
找出最大的前K個數
是程式設計之美裡的乙個問題,找出乙個列表中的最大的前k個數,最先想到,也是最簡單的思路是做乙個k長度的盒子,然後乙個乙個資料往裡放,有大的來了就把小的剔除掉。但是這樣的做法會導致盒子內部要是有序的。不然找不出誰是最小的,比較和剔除就不能做了 這個做法的複雜度是o n k 書裡面講了一種比較好的辦法,...