1. 程式人生 > 其它 >【排序】力扣347:前K個高頻元素(未完)

【排序】力扣347:前K個高頻元素(未完)

給你一個整數陣列 nums 和一個整數 k ,請你返回其中出現頻率前 k 高的元素。你可以按 任意順序 返回答案。

示例:

輸入: nums = [1,1,1,2,2,3], k = 2
輸出: [1,2]

進階:你所設計演算法的時間複雜度 必須 優於 O(nlogn) ,其中 n 是陣列大小。

3種方法:部分快排思想;直接排序;優先佇列

方法1:最小堆

  1. 藉助【雜湊表】來建立數字和其出現次數的對映,遍歷一遍陣列統計元素的頻率
  2. 維護一個元素數目為 k 的最小堆
  3. 每次都將新的元素與堆頂元素(堆中頻率最小的元素)進行比較
  4. 如果新的元素的頻率比堆頂端的元素大,則彈出堆頂端的元素,將新的元素新增進堆中
  5. 最終,堆中的 k 個元素即為前 k 個高頻元素

作者:cxywushixiong
連結:https://leetcode-cn.com/problems/top-k-frequent-elements/solution/leetcode-di-347-hao-wen-ti-qian-k-ge-gao-pin-yuan-/

時間複雜度:O(nlogk),n 表示陣列的長度。首先,遍歷一遍陣列統計元素的頻率,這一系列操作的時間複雜度是O(n);接著,遍歷用於儲存元素頻率的 map,如果元素的頻率大於最小堆中頂部的元素,則將頂部的元素刪除並將該元素加入堆中,這裡維護堆的數目是 k,所以這一系列操作的時間複雜度是 O(nlogk) 的;因此,總的時間複雜度是 O(nlog⁡k)。
空間複雜度:O(n),最壞情況下(每個元素都不同),map 需要儲存 n 個鍵值對,優先佇列需要儲存 k 個元素,因此,空間複雜度是 O(n)。

方法2:桶排序
設定若干個桶,每個桶儲存出現頻率相同的數。桶的下標表示數出現的頻率,即第 i 個桶中儲存的數出現的頻率為 i。
把數都放到桶之後,從後向前遍歷桶,最先得到的 k 個數就是出現頻率最多的的 k 個數。

首先依舊使用雜湊表統計頻率,統計完成後,建立一個數組,將頻率作為陣列下標,對於出現頻率不同的數字集合,存入對應的陣列下標即可。


時間複雜度:O(n),n 表示陣列的長度。首先,遍歷一遍陣列統計元素的頻率,這一系列操作的時間複雜度是 O(n);桶的數量為 n+1,所以桶排序的時間複雜度為 O(n);因此,總的時間複雜度是 O(n)。
空間複雜度:很明顯為 O(n)。

方法3:python的Counter()


統計每個數的頻率,輸出最大的幾個,這完全迎合了Python中的Counter類,呼叫其的幾個方法即可。

Counter 是一個在collections包裡的類,正如其名,是一個用於計數的工具。
我們可以用Counter(nums)這樣的建構函式構造一個Counter類,其中nums是一個列表。
構造好的Counter例項可以看作一個字典,鍵是nums的每一項,值是它的出現次數。
如果上面的敘述讓你感到很混亂的話,我不妨舉個例子。
如果一個列表a = [1,1,3,4,3],你想要統計每項的出現次數,那麼你使用b = Counter(a),那麼這時候b就像一個這樣的字典{1:2,3:2,4:1},表示數字1出現了2次,數字3出現了2次,數字4出現了1次。
可是題目裡要我們輸出的是最多的K項,這時候可以應用Counter的一個函式,most_common(k),這個函式就是返回最多出現的K項
但是返回的形式是一個元祖列表,類似[(1,2),(3,2),(4,1)]的形式,我們只需要鍵也就是第一項,所以要使用列表生成式處理一下即可。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        from collections import Counter
        return [i[0] for i in Counter(nums).most_common(k)]

作者:qsctech-sange
連結:https://leetcode-cn.com/problems/top-k-frequent-elements/solution/yi-xing-python3dai-ni-zou-jin-counterlei-by-jimmy0/