leetcode-347前K個高頻元素

2021-03-02 子木筆記

347前K個高頻元素 https://leetcode-cn.com/problems/top-k-frequent-elements/

1、題目描述

給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。


示例 1:

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

輸出: [1,2]

示例 2:

輸入: nums = [1], k = 1

輸出: [1]

提示:

你可以假設給定的 k 總是合理的,且 1 ≤ k ≤ 數組中不相同的元素的個數。你的算法的時間複雜度必須優於 O(n log n) , n 是數組的大小。題目數據保證答案唯一,換句話說,數組中前 k 個高頻元素的集合是唯一的。2、思路

都需要通過一個map統計各個數字出現的頻率,區別在如何對統計的map數據進行處理獲取前topk個元素

思路1:通過把map的key,value封裝對象,通過優先級隊列維護一個K個大小的最小堆。時間複雜度O(nlogk),空間複雜度N

思路2:在統計數字出現個數時,同時計算出,最大頻率max,然後按照頻率構建桶排序數組,遍歷數組即可獲得結果。時間複雜度N,空間複雜度 N(可能存在max很大而申請的數組浪費空間)

思路3:使用treemap,頻率為key,value為當前頻率下的元素。依次獲取treemap的尾部元素直到夠K個即可。

3、題解

思路1

//思路1:先通過map統計各個數字出現的頻率,然後通過優先級隊列列構建小頂堆,取最大的topk
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k <= 0) {
            int[] res = {};
            return res;
        }
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int key = nums[i];
            if (map.containsKey(key)) {
                map.put(key,map.get(key) + 1);
            } else {
                map.put(key, 1);
            }
        }
        //使用優先級隊列構建小頂堆,取最大的topk
        PriorityQueue<Pair> queue = new PriorityQueue<>(new Comparator<Pair>(){
            public int compare(Pair p1,Pair p2) {
                return p1.count - p2.count;
            }
        });
        for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
            Pair pair = new Pair(entry.getKey(),entry.getValue());
            queue.offer(pair);
            if (queue.size() > k) {
                queue.poll();
            }
        }
        int[] res = new int[k];
        for (int i = 0; i < k; i++) {
            res[i] = queue.poll().key;
        }
        return res;
    }

    class Pair{
        int key;
        int count;
        public Pair(int key,int count) {
            this.key = key;
            this.count = count;
        }
    }
}


//優化上面的代碼,優先級隊列直接存儲Map.Entry,按照統計個數進行構建最小堆
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k <= 0) {
            int[] res = {};
            return res;
        }
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int key = nums[i];
            if (map.containsKey(key)) {
                map.put(key,map.get(key) + 1);
            } else {
                map.put(key, 1);
            }
        }
        //使用優先級隊列構建小頂堆,取最大的topk
        PriorityQueue<Map.Entry<Integer,Integer>> queue = 
        new PriorityQueue<Map.Entry<Integer,Integer>>(
            new Comparator<Map.Entry<Integer,Integer>>(){
            public int compare(Map.Entry<Integer,Integer> entry1,Map.Entry<Integer,Integer> entry2) {
                return entry1.getValue() - entry2.getValue();
            }
        });
        for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
            queue.offer(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }
        int[] res = new int[k];
        for (int i = 0; i < k; i++) {
            res[i] = queue.poll().getKey();
        }
        return res;
    }
        
}

思路2

//思路2:藉助於桶排序找k個最大數
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        //1、統計每個數字出現的個數
        Map<Integer,Integer> map = new HashMap<>();
        int max = 0;
        for (int i = 0;i < nums.length;i++) {
            map.put(nums[i], map.get(nums[i]) != null ? map.get(nums[i]) + 1 : 1);
            //出現頻率最大的個數
            max = Math.max(max, map.get(nums[i]));
        }
        //2、構建一個桶,通過各個出現相同頻率的放在一個桶中(出現的頻率分桶)
        List<Integer>[] dp = new List[max + 1];
        for (Integer i : map.keySet()) {
            int frequent = map.get(i);
            if (dp[frequent] == null) dp[frequent] = new ArrayList<>();
            dp[frequent].add(i);
        }
        int p = 0;
        //3、逆序遍歷桶,找夠K個數
        for (int i = dp.length - 1;i >= 0 && p < k;i--) {
            List<Integer> temp = dp[i];
            if (temp != null) {
                for (Integer j : temp) {
                    if (p == k) return res;
                    res[p++] = j;
                }
            }
        }
        return  res;
    }
}

思路3

//思路3:藉助於treemap找k個最大數
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k <= 0) {
            int[] res = {};
            return res;
        }
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i],map.getOrDefault(nums[i],0) + 1);
        }
        TreeMap<Integer,List<Integer>> treemap = new TreeMap<>();
        
        for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
            if (!treemap.containsKey(entry.getValue())) {
                treemap.put(entry.getValue(),new LinkedList<Integer>());
            }
            treemap.get(entry.getValue()).add(entry.getKey());
        }
        int[] res = new int[k];
        int i = 0;
        while (i < k) {
            Map.Entry<Integer,List<Integer>> entry = treemap.pollLastEntry();
            for (int j = 0; j < entry.getValue().size(); j++) {
                res[i++] =  entry.getValue().get(j);
            }
        }
        return res;
    }
        
}

相關焦點

  • top k frequent words(前K個高頻單詞)
    問題給一非空的單詞列表,返回前 k 個出現次數最多的單詞。返回的答案應該按單詞出現頻率由高到低排序。
  • [LeetCode] 973. K Closest Points to Origin 最接近原點的K個點
    排好序之後,返回前k個點即可,參見代碼如下:解法一:class Solution {public: vector<vector<int>> kClosest(vector<vector<int>>& points, int K) { sort(points.begin
  • 341,前 K 個高頻元素
    給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。
  • leetcode-378有序矩陣中第 K 小的元素
    3、二分法,時間複雜度logN,空間複雜度1[最優]378有序矩陣中第 K 小的元素 https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/1、題目描述給你一個 n x n 矩陣 matrix
  • LeetCode-23.合併K個排序鍊表(Merge k Sorted Lists)
    這是前面Merge Two Sorted Lists的一個follow-up排序超大數量級的數據,可以分成N個機器分別排序
  • LeetCode-25.K個一組翻轉鍊表(Reverse Nodes in k-Group)
    K個一組翻轉鍊表給你一個鍊表,每 k 個節點一組進行翻轉,請你返回翻轉後的鍊表。k 是一個正整數,它的值小於或等於鍊表的長度。如果節點總數不是 k 的整數倍,那麼請將最後剩餘的節點保持原有順序。示例:給你這個鍊表:1->2->3->4->5當 k = 2 時,應當返回: 2->1->4->3->5當 k = 3 時,應當返回: 3->2->1->4->5說明:你的算法只能使用常數的額外空間。
  • leetcode-215數組中的第K個最大元素
    215數組中的第K個最大元素 https://leetcode-cn.com/problems/kth-largest-element-in-an-array/1、題目描述在未排序的數組中找到第 k 個最大的元素。
  • 每天一道leetcode378-有序矩陣中第K小的元素
    分類:二分查找類給定一個 n x n 矩陣,其中每行和每列元素均按升序排序,找到矩陣中第k小的元素。請注意,它是排序後的第k小元素,而不是第k個元素。示例:matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15]],k = 8,返回 13。
  • ​LeetCode刷題實戰25:K 個一組翻轉鍊表
    今天和大家聊的問題叫做K 個一組翻轉鍊表,我們先來看題面:https://leetcode-cn.com/problems/reverse-nodes-in-k-groupGiven a linked list, reverse the nodes of a linked list k at a time and return its
  • LeetCode 23. Merge k Sorted Lists
    [傳送門](https://leetcode.com/problems/merge-k-sorted-lists/)## 題意
  • 詳解一道高頻算法題:數組中的第 K 個最大元素
    今天分享的題目來源於 LeetCode 第 215 號問題,是面試中的高頻考題。在 未排序 的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序後的第 k 個最大的元素,而不是第 k 個不同的元素。
  • LeetCode刷題第三周【數組(簡單)】
    刷題前我們來了解一下什麼是數組:數組是在程序設計中,為了處理方便, 把具有相同類型的若干元素按有序的形式組織起來的一種形式。首先,數組會利用 索引 來記錄每個元素在數組中的位置,且在大多數程式語言中,索引是從 0 算起的。我們可以根據數組中的索引,快速訪問數組中的元素。事實上,這裡的索引其實就是內存地址。
  • LeetCode Weekly Contest 204 題解
    Detect Pattern of Length M Repeated K or More Times題目連結:https://leetcode.com/problems/detect-pattern-of-length-m-repeated-k-or-more-times/題解連結:https://github.com/yular/CC--InterviewProblem
  • Leetcode weekly contest三月小結
    maxSize,同時要求實現一個increment(k, val)方法,把棧裡底部的k個數值分別增加val。解法:看起來非常的straightforward,維護一個數組當成棧,只從數組的右端進行push/pop操作,然後再increment()函數裡面把數組的前k個數值增加即可,也是能通過比賽中的所有test cases。這裡的increment函數的時間複雜度是O(min(k, maxSize))。有沒有更優的辦法呢,其實是有的。
  • 我說你在 LeetCode 練死勁不好用,他說你這也沒用,我說我這個有用.
    面試前按照意向公司面試高頻題準備一下,做到心中有數。例如最近剛剛發現的 Github 上很有意思的一個 Repo,總結了幾大廠面試高頻題目。例如,這是裡面關於字節跳動的一些題目節選:出現次數連結25.K 個一組翻轉鍊表21https://leetcode-cn.com/problems/reverse-nodes-in-k-group3. 無重複字符的最長子串19https://leetcode-cn.com/problems/longest-substring-without-repeating-characters15.
  • LeetCode Top 100 高頻算法題 23. Merge k Sorted Lists
    今日推薦:LeetCode Top 100高頻算法題
  • LeetCode-75.顏色分類(Sort Colors)
    顏色分類給定一個包含紅色、白色和藍色,一共 n 個元素的數組,原地對它們進行排序,使得相同顏色的元素相鄰,並按照紅色、白色、藍色順序排列。此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。注意:不能使用代碼庫中的排序函數來解決這道題。
  • AK leetcode 流浪計劃 - 回文串
    isNeedCheck(s[i]); i++ {} // 查找到第1個需要比較的元素  for ; i < j && !isNeedCheck(s[j]); j-- {} // 查找最後一個需要比較的元素  if s[i] !