LeetCode 熱題 100_前 K 個高頻元素(73_347_中等_C++)(堆)(哈希表+排序;哈希表+優先隊列(小根堆))

LeetCode 熱題 100_前 K 個高頻元素(73_347)

    • 題目描述:
    • 輸入輸出樣例:
    • 題解:
      • 解題思路:
        • 思路一(哈希表+排序):
        • 思路二(哈希表+優先隊列(小根堆)):
      • 代碼實現
        • 代碼實現(思路一(哈希表+排序)):
        • 代碼實現(思路二(哈希表+優先隊列(小根堆))):
        • 以思路二為例進行調試
        • 部分代碼解讀

題目描述:

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

輸入輸出樣例:

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

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

提示:
1 <= nums.length <= 105
k 的取值范圍是 [1, 數組中不相同的元素的個數]
題目數據保證答案唯一,換句話說,數組中前 k 個高頻元素的集合是唯一的

題解:

解題思路:

思路一(哈希表+排序):

1、創建一個哈希表,key來存儲數組中元素,value存儲對應key出現的次數。對value進行快速排序。提取排序后,前k個元素的值。

2、復雜度分析:
① 時間復雜度:O(nlogn),n為數組中元素的個數
????遍歷 nums 數組中的每個元素,將其出現的頻率存儲到 unordered_map 中。這個過程的時間復雜度是 O(n)。
????將 unordered_map 的元素復制到 vector 中,這個操作的時間復雜度是 O(n)。
????對 tmp 中的元素進行排序,排序的時間復雜度是 O(n log n)。
????從排序后的 tmp 中選擇前 k 個元素并將它們添加到 ans 中,這個過程的時間復雜度是 O(k)。
② 空間復雜度:O(n + log n),除返回答案的空間外,unordered_map 的空間復雜度是 O(n),vector<pair<int, int>> tmp 的空間復雜度是 O(n)。快速排序,空間復雜度是 O(log n)

思路二(哈希表+優先隊列(小根堆)):

1、創建一個哈希表,key來存儲數組中元素,value存儲對應key出現的次數。創建可以維持 k 個元素的小根堆(根據value大小進行插入),這樣在插入元素大于 k 時可以將堆頂的元素移出(優先級隊列就是一個披著隊列外衣的堆)。

2、復雜度分析
① 時間復雜度:O(n log k),其中 n 是輸入數組的長度,k 是要求的前 k 個頻率最高的元素。遍歷 nums 數組并將每個元素的出現頻率存入 unordered_map中為 O(n)。將元素插入最小堆O(n log k)。從堆中彈出元素并構建結果數組 O(k log k)。
② 空間復雜度: O(n + k),哈希表存儲每個數字及其頻率,最壞情況下需要存儲所有 n 個數字 O(n)。最小堆的最大大小為 O(k)。

代碼實現

代碼實現(思路一(哈希表+排序)):
class Solution1 {
public:// 函數接受一個整數數組 nums 和一個整數 k, 返回出現頻率最高的 k 個元素vector<int> topKFrequent(vector<int>& nums, int k) {// 使用 unordered_map 來統計每個數字出現的頻率unordered_map<int,int> count;// 遍歷 nums 數組,統計每個數字的出現次數for (int &num : nums){count[num]++; // 每遇到一個 num,就將對應的頻率加 1}// 將 unordered_map 中的元素復制到一個 vector 中,以便進行排序vector<pair<int,int>> tmp(count.begin(), count.end());// 對 tmp 中的元素進行排序,按照頻率降序排序// 使用 lambda 表達式作為排序規則sort(tmp.begin(), tmp.end(), [](pair<int,int>& a, pair<int,int>& b) { return a.second > b.second; // 如果 a 的頻率大于 b 的頻率,返回 true });// 創建一個結果 vector 來存放出現頻率最高的 k 個元素vector<int> ans;// 選擇排序后的前 k 個元素的第一個值(即數字)到 ans 中for (int i = 0; i < k; i++){ans.emplace_back(tmp[i].first); // 將 tmp 中的第 i 個元素的第一個值添加到 ans}return ans; // 返回結果}
};
代碼實現(思路二(哈希表+優先隊列(小根堆))):
class Solution2 {
private:// 自定義比較器類,用于堆的排序class Compare {public:// 重載比較運算符,按照頻率(second)大小進行比較bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {// 如果左邊的頻率大于右邊,返回true。這樣堆中頻率小的元素會排在堆頂。return lhs.second > rhs.second;}};public:// topKFrequent 函數返回數組中出現頻率前k大的元素vector<int> topKFrequent(vector<int>& nums, int k) {// 使用 unordered_map 來存儲每個元素及其出現的頻率unordered_map<int, int> count;// 統計數組中每個元素的出現次數for (int i = 0; i < nums.size(); i++) {count[nums[i]]++;}// 創建一個最小堆來保存頻率前 k 大的元素// priority_queue 的第三個參數是自定義的比較器 Compare,確保堆頂是頻率最小的元素priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> min_head;// 遍歷計數哈希表,將每個元素(和其頻率)加入到堆中for (auto& i : count) {min_head.push(i); // 將元素及其頻率壓入堆// 如果堆的大小超過了 k,則彈出堆頂元素(頻率最小的元素)if (min_head.size() > k) {min_head.pop();}}// 用來存儲最終的前 k 個頻率最大的元素vector<int> ans(k);// 從堆中依次彈出元素,存入答案數組// 由于堆頂是頻率最小的元素,因此我們從堆頂彈出并將元素存入結果數組for (int i = k - 1; i >= 0; i--) {ans[i] = min_head.top().first; // 獲取堆頂元素的值(即數字)min_head.pop(); // 彈出堆頂元素}return ans; // 返回包含頻率前 k 大的元素的數組}
};
以思路二為例進行調試
#include<iostream>
#include <vector>
#include<unordered_map>
#include<algorithm>
#include <queue>
using namespace std;class Solution2 {
private:// 自定義比較器類,用于堆的排序class Compare {public:// 重載比較運算符,按照頻率(second)大小進行比較bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {// 如果左邊的頻率大于右邊,返回true。這樣堆中頻率小的元素會排在堆頂。return lhs.second > rhs.second;}};public:// topKFrequent 函數返回數組中出現頻率前k大的元素vector<int> topKFrequent(vector<int>& nums, int k) {// 使用 unordered_map 來存儲每個元素及其出現的頻率unordered_map<int, int> count;// 統計數組中每個元素的出現次數for (int i = 0; i < nums.size(); i++) {count[nums[i]]++;}// 創建一個最小堆來保存頻率前 k 大的元素// priority_queue 的第三個參數是自定義的比較器 Compare,確保堆頂是頻率最小的元素priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> min_head;// 遍歷計數哈希表,將每個元素(和其頻率)加入到堆中for (auto& i : count) {min_head.push(i); // 將元素及其頻率壓入堆// 如果堆的大小超過了 k,則彈出堆頂元素(頻率最小的元素)if (min_head.size() > k) {min_head.pop();}}// 用來存儲最終的前 k 個頻率最大的元素vector<int> ans(k);// 從堆中依次彈出元素,存入答案數組// 由于堆頂是頻率最小的元素,因此我們從堆頂彈出并將元素存入結果數組for (int i = k - 1; i >= 0; i--) {ans[i] = min_head.top().first; // 獲取堆頂元素的值(即數字)min_head.pop(); // 彈出堆頂元素}return ans; // 返回包含頻率前 k 大的元素的數組}
};int main(int argc, char const *argv[])
{vector<int> nums={1,1,1,2,2,3};int k=2;Solution2 s2;vector<int> ans=s2.topKFrequent(nums,k);cout<<"[";for (int i = 0; i < ans.size(); i++){cout<<ans[i];if (i!=ans.size()-1){cout<<",";}}cout<<"]";return 0;
}
部分代碼解讀

比較器是 lambda 表達式

sort(tmp.begin(), tmp.end(), [](pair<int,int>& a, pair<int,int>& b) { return a.second > b.second; // 如果 a 的頻率大于 b 的頻率,返回 true 
});

最常見的比較器是 lambda 表達式,因為它:
非常簡潔,適用于大多數場景,特別是排序、查找等常用算法。
可以在需要時動態定義比較邏輯,而不需要額外定義函數或類。

Compare:自定義比較器類 (Functor)

class Compare {
public:// 重載比較運算符,按照頻率(second)大小進行比較bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {// 如果左邊的頻率大于右邊,返回true。這樣堆中頻率小的元素會排在堆頂。return lhs.second > rhs.second;}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> min_head;

Compare:自定義比較器類 (Functor)
pair<int, int> 是一個由兩個 int 類型元素組成的模板類,它可以存儲一對值。
這里的 vector<pair<int, int>> 表示堆的底層容器是一個 pair<int, int> 類型的 vector。
優點:
復用性強:可以在多個地方使用相同的比較邏輯,不需要每次都重新定義。
性能較好:在某些情況下,函數對象(類)可能比 lambda 表達式稍微高效,因為它可以在編譯時優化。
適合復雜邏輯:當比較邏輯較復雜時,使用類比 lambda 更加清晰和易于管理。
缺點:
代碼較多:需要定義一個額外的類,增加了代碼的復雜性,尤其是對于簡單的比較。

LeetCode 熱題 100_前 K 個高頻元素(73_347)原題鏈接
歡迎大家和我溝通交流(????)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73343.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73343.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73343.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Python在Word中生成多種不同類型的圖表

目錄 工具與環境配置 在 Word 中創建圖表的步驟 在Word中創建柱形圖 在Word中創建條形圖 在Word中創建折線圖 在Word中創建餅圖 在Word中創建散點圖 在Word中創建氣泡圖 在 Word 文檔中插入圖表不僅能更直觀地呈現數據&#xff0c;還能提升文檔的可讀性和專業性。常見的…

項目-個人博客測試報告

目錄 一、項目背景 二、項目功能 三、測試計劃 &#xff08;1&#xff09;功能測試 &#xff08;2&#xff09;自動化測試 &#xff08;3&#xff09;性能測試 一、項目背景 1、個人博客系統是一個操作簡單的基于Spring前后端分離的項目&#xff0c;同時使用MySQL數據庫來進…

前端npm包- CropperJS

文章目錄 一、CropperJS**核心特性****官網與文檔****安裝與使用**1. **通過 npm/yarn/pnpm 安裝**2. **HTML 結構**3. **引入 CSS 和 JS**4. **初始化裁剪器** **相關插件/替代方案****適用場景****注意事項** 總結 一、CropperJS cropperjs 是一個輕量級、功能強大的 圖片裁…

楊輝三角形(信息學奧賽一本通-2043)

【題目描述】 例5.11 打印楊輝三角形的前n(2≤n≤20)行。楊輝三角形如下圖&#xff1a; 當n5時 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 輸出&#xff1a; 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 【輸入】 輸入行數n。 【輸出】 輸出如題述三角形。n行&#…

圖論入門【數據結構基礎】:什么是圖?如何表示圖?

圖&#xff08;Graph&#xff09; 是一種非線性數據結構&#xff0c;用于表示對象之間的關系。圖由 頂點&#xff08;Vertex&#xff09; 和 邊&#xff08;Edge&#xff09; 組成&#xff0c;其中頂點表示對象&#xff0c;邊表示對象之間的關系。圖廣泛應用于計算機科學、數學…

如何使用HACS一鍵集成米家與果家設備到HomeAssistant玩轉智能家居

文章目錄 前言1. 下載HACS源碼2. 添加HACS商店3. 綁定米家設備 前言 各位科技潮人和智能家居發燒友們&#xff0c;是不是也夢想著把家里變成一個高科技的空間&#xff1f;有了群暉NAS這位得力助手&#xff0c;不僅存儲空間大得嚇人&#xff0c;還能通過Docker輕松安裝各種應用…

《Java對象“比武場“:Comparable與Comparator的巔峰對決》

目錄 引言&#xff1a; 一、認識接口 1.1 Comparable 1.2 Comparator ?編輯 1.3 核心概念對比 二、代碼實現對比 2.1 Comparable 實現示例 2.2 Comparator 實例示例 三、核心區別詳解 3.1 設計理念差異 3.2 方法調用 3.3 使用情景 四、本質區別總結 引言&#x…

Android自動化測試工具

細解自動化測試工具 Airtest-CSDN博客 以下是幾種常見的Android應用自動化測試工具&#xff1a; Appium&#xff1a;支持多種編程語言&#xff0c;如Java、Python、Ruby、JavaScript等。可以用于Web應用程序和原生應用程序的自動化測試&#xff0c;并支持iOS和Android平臺。E…

Go vs Rust vs C++ vs Python vs Java:誰主后端沉浮

一、核心性能對比(基于TechEmpower基準測試) 語言單核QPS延遲(ms)內存消耗適用場景Rust650,0000.1245MB高頻交易/區塊鏈C++720,0000.0932MB游戲服務器/實時渲染Go230,0000.45110MB微服務/API網關Java180,0001.2450MB企業ERP/銀行系統Python12,0008.5220MBAI接口/快速原型技術…

vue3:八、登錄界面實現-頁面初始搭建、基礎實現

一、初始工作 1、創建登錄文件 在src/views中創建文件LoginView.vue文件 2、創建路由 在router/index.js中增加登錄的信息 代碼 import { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vue const router createRouter({hist…

結構型模式之適配器模式:讓不兼容的接口兼容

在軟件開發中&#xff0c;經常會遇到這樣一種情況&#xff1a;系統的不同部分需要進行交互&#xff0c;但由于接口不兼容&#xff0c;導致無法直接使用。這時&#xff0c;適配器模式&#xff08;Adapter Pattern&#xff09;就能派上用場。適配器模式是設計模式中的結構型模式&…

Qt從入門到入土(十) -數據庫操作--SQLITE

認識 數據庫是用于存儲、管理和檢索數據的系統化集合。它是一種按照特定結構組織數據的存儲方式&#xff0c;通過軟件&#xff08;數據庫管理系統&#xff0c;DBMS&#xff09;來實現數據的高效存儲、查詢、更新和管理。通過文件存儲數據適用于少量的數據&#xff0c;而當擁有…

Django REST Framework中的序列化器類和視圖類

序列化器類 一、Serializer序列化類 Serializer是DRF的序列化器基類&#xff0c;提供基本功能&#xff0c;使用Serializer類需要自己定義字段名稱和類型。 BookSerializer(Serializer):name serializers.CharField()price serlializers.IntegerField()date serlializers.…

圖像分類數據集

《動手學深度學習》-3.5-學習筆記 # 通過ToTensor實例將圖像數據從PIL類型變換成32位浮點數格式&#xff0c; # 并除以255使得所有像素的數值均在0&#xff5e;1之間 trans transforms.ToTensor()#用于將圖像數據從 PIL 圖像格式&#xff08;Python Imaging Library&#xff…

架構師面試(十五):熔斷設計

問題 某電商平臺經常需要在大促運營活動中暫停評論、退款等業務&#xff0c;基于服務治理的設計理念&#xff0c;我們需要對該電商平臺微服務系統的【服務熔斷】進行設計&#xff0c;對此下面描述中說法正確的有哪幾項呢&#xff1f; A. 服務管控系統管理著平臺中所有服務之間…

Ubuntu20.04安裝運行DynaSLAM

目錄 一、安裝Anaconda 二、相關依賴庫安裝 1、boost安裝 2、Eigen 3安裝 3、opencv安裝 4、Pangolin安裝 三、配置Mask_RCNN環境 四、DynaSLAM編譯 五、DynaSLAM運行 一、安裝Anaconda 打開以下鏈接&#xff1a; Index of / 下載和自己系統匹配的安裝包。這里下…

X86 RouterOS 7.18 設置筆記三:防火墻設置(IPV4)

X86 j4125 4網口小主機折騰筆記五&#xff1a;PVE安裝ROS RouterOS X86 RouterOS 7.18 設置筆記一&#xff1a;基礎設置 X86 RouterOS 7.18 設置筆記二&#xff1a;網絡基礎設置(IPV4) X86 RouterOS 7.18 設置筆記三&#xff1a;防火墻設置(IPV4) X86 RouterOS 7.18 設置筆記四…

從 YOLOv1 到 YOLOv2:目標檢測的進化之路

引言 你有沒有想過&#xff0c;當你用手機拍一張照片&#xff0c;里面的人、車、狗是怎么被自動識別出來的&#xff1f;這背后靠的就是目標檢測技術。目標檢測是計算機視覺中的一個重要領域&#xff0c;它不僅要回答“圖片里有什么”&#xff0c;還要告訴你“這些東西在哪里”…

數據的存儲---整型、浮點型

目錄 一、整型在內存中的存儲 1. 原碼、反碼、補碼 2. 大端與小端 二、浮點數在內存中的存儲 1.浮點數的存 2. 浮點數的取 3. 題目解析 一個變量的創建需要在內存中開辟空間&#xff0c;而開辟的空間大小是由數據類型決定的。下面我們就來討論一下整型、浮點型在內存中的…

Java 大視界 -- Java 大數據在智能教育虛擬實驗室建設與實驗數據分析中的應用(132)

&#x1f496;親愛的朋友們&#xff0c;熱烈歡迎來到 青云交的博客&#xff01;能與諸位在此相逢&#xff0c;我倍感榮幸。在這飛速更迭的時代&#xff0c;我們都渴望一方心靈凈土&#xff0c;而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識&#xff0c;也…