出現次數的TopK問題
阿新 • • 發佈:2020-12-29
技術標籤:程式設計師程式碼面試指南
出現次數的TopK問題
題目描述
給定String型別的陣列strArr,再給定整數k,請嚴格按照排名順序列印 出次數前k名的字串。
[要求]
如果strArr長度為N,時間複雜度請達到 O ( N log K ) O(N \log K) O(NlogK)
輸入描述:
第一行兩個整數N, k。N表示陣列大小
接下來N行,每行一個字串
輸出描述:
輸出K行,每行有一個字串和一個整數。
你需要按照出現出現次數由小到大輸出,若出現次數相同時字串字典序較小的優先輸出
示例1
輸入
4 2
1
2
3
4
輸出
1 1
2 1
示例2
輸入
4 2 1 1 2 3
輸出
1 2
2 1
備註:
1
⩽
N
⩽
1
0
5
1 \leqslant N \leqslant 10^5
1⩽N⩽105
∑
字元個數
⩽
1
0
5
\sum \text{字元個數} \leqslant 10^5
∑字元個數⩽105
1 ⩽ k ⩽ 本質不同的字串數 1 \leqslant k \leqslant \text{本質不同的字串數} 1⩽k⩽本質不同的字串數
保證輸入的字串僅含有大小寫字母/數字
題解:
一般涉及到 TopK 問題,首先應該考慮用堆。
- 首先,使用雜湊表統計每個字串的出現次數,時間複雜度 O ( n ) O(n) O(n);
- 然後,將雜湊表的前 k 個元素插入到小根堆中,接著遍歷雜湊表剩下的元素,將其插入到小根堆中,始終保持堆中元素個數為 k 個,時間複雜度
O
(
n
l
o
g
k
)
O(nlogk)
- 最後,將堆中的元素排序,頻率從小到大,時間複雜度 O ( k l o g k ) O(klogk) O(klogk)。
所以,最終的時間複雜度為 O ( n l o g k ) O(nlogk) O(nlogk)。
程式碼:
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
typedef pair<string, int > PSI;
class MyCompare {
public:
bool operator()( const PSI& a, const PSI& b) const {
if ( a.second == b.second )
return a.first < b.first;
return a.second > b.second;
}
};
int main(void) {
ios_base::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, k;
cin >> n >> k;
unordered_map<string, int> hash;
string str;
while ( n-- ) {
cin >> str;
hash[str] += 1;
}
priority_queue<PSI, vector<PSI>, MyCompare > heap;
for ( auto& it : hash ) {
if ( heap.size() != k ) heap.push( it );
else {
auto top = heap.top();
if ( top.second == it.second && top.first > it.first
|| top.second < it.second ) {
heap.pop();
heap.push( it );
}
}
}
vector<PSI> ans;
while ( heap.size() ) {
ans.push_back( heap.top() );
heap.pop();
}
for ( int i = k - 1; i >= 0; --i ) {
cout << ans[i].first << ' ' << ans[i].second << endl;
}
return 0;
}