1. 程式人生 > 其它 >出現次數的TopK問題

出現次數的TopK問題

技術標籤:程式設計師程式碼面試指南

出現次數的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 1N105
∑ 字元個數 ⩽ 1 0 5 \sum \text{字元個數} \leqslant 10^5 字元個數105

1 ⩽ k ⩽ 本質不同的字串數 1 \leqslant k \leqslant \text{本質不同的字串數} 1k本質不同的字串數

保證輸入的字串僅含有大小寫字母/數字


題解:

一般涉及到 TopK 問題,首先應該考慮用堆。

  • 首先,使用雜湊表統計每個字串的出現次數,時間複雜度 O ( n ) O(n) O(n)
  • 然後,將雜湊表的前 k 個元素插入到小根堆中,接著遍歷雜湊表剩下的元素,將其插入到小根堆中,始終保持堆中元素個數為 k 個,時間複雜度 O ( n l o g k ) O(nlogk)
    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; }