[Lc14_priority_queue] 最后一塊石頭重量 | 數據流中的第 K 大元素 | 前K個高頻單詞 | 數據流的中位數

目錄

1.最后一塊石頭的重量

題解

2.數據流中的第 K 大元素

題解

3.前K個高頻單詞

題解

代碼

?4.數據流的中位數

題解


在C++中,使用標準庫中的priority_queue,默認情況下它是一個最大堆(即大堆排序),這意味著最大的元素總是位于隊列的前面。具體來說,默認使用的比較器是std::less<T>

1.最后一塊石頭的重量

鏈接:1046. 最后一塊石頭的重量

有一堆石頭,每塊石頭的重量都是正整數。

每一回合,從中選出兩塊 最重的 石頭,然后將它們一起粉碎。假設石頭的重量分別為 xy,且 x <= y。那么粉碎的可能結果如下:

  • 如果 x == y,那么兩塊石頭都會被完全粉碎;
  • 如果 x != y,那么重量為 x 的石頭將會完全粉碎,而重量為 y 的石頭新重量為 y-x

最后,最多只會剩下一塊石頭。返回此石頭的重量。如果沒有石頭剩下,就返回 0

示例:

輸入:[2,7,4,1,8,1]
輸出:1
解釋:
先選出 7 和 8,得到 1,所以數組轉換為 [2,4,1,1,1],
再選出 2 和 4,得到 2,所以數組轉換為 [2,1,1,1],
接著是 2 和 1,得到 1,所以數組轉換為 [1,1,1],
最后選出 1 和 1,得到 0,最終數組轉換為 [1],這就是最后剩下那塊石頭的重量。

題解

  • 每一回合,從中選出兩塊 最重的 石頭,x == y,那么兩塊石頭都會被完全粉碎;
  • 如果 x != y,那么重量較小的 x 石頭將會完全粉碎,而重量較大的 y 的石頭新重量為 y-x。
  • 最多只會剩下一塊石頭。

返回此石頭的重量。如果沒有石頭剩下,就返回 0。

每次挑選的是先挑一堆數中最大的那個數,然后再挑一個剩下數中最大的數。

這不正好符合大根堆的數據結構嗎。

解法:用堆來模擬這個過程

先拿數組的數創建一個大根堆,每次從堆里面 選擇最大和次大兩個數

  • 如果相等就是0不用加入到大根堆里
  • 如果不相等用最大的數減去次大的數,把結果加入到堆里面。

如果最后堆里還剩下一個數,返回這個數。如果堆為空說明石頭全都粉碎了返回0即可。

class Solution {
public:int lastStoneWeight(vector<int>& stones) {priority_queue<int> heap;for(auto& n:stones)heap.push(n);while(heap.size()>1){int n1=heap.top();heap.pop();int n2=heap.top();heap.pop();if(n1==n2) continue;else{int tmp=n1>n2?n1-n2:n2-n1;heap.push(tmp);}}return heap.empty()?0:heap.top();   }
};

2.數據流中的第 K 大元素

鏈接:703. 數據流中的第 K 大元素

設計一個找到數據流中第 k 大元素的類(class)。注意是排序后的第 k 大元素,不是第 k 個不同的元素。

請實現 KthLargest 類:

  • KthLargest(int k, int[] nums) 使用整數 k 和整數流 nums 初始化對象。
  • int add(int val)val 插入數據流 nums 后,返回當前數據流中第 k 大的元素。

示例 1:

輸入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]

輸出:[null, 4, 5, 5, 8, 8]


題解

設計一個找到數據流中第 k 大元素的類(class)。

注意是 排序后的第 k 大元素,不是第 k 個不同的元素。

int add(int val) 將 val 插入數據流 nums 后,返回當前數據流中第 k 大的元素。

這道題其實考察的是一個非常經典的問題, TopK問題。

  • 關于TopK問題有兩種解題思路,一種是堆 O(nlogk),一種是前面剛學的快速選擇算法 O(n)(前文回顧:[Lc7_分治-快排] 快速選擇排序 | 數組中的第K個最大元素 | 庫存管理 III。
  • 快速選擇排序雖然快,但是對于海量的數據內存根本放不下。
  • 所以在海量數據情況最優的還是堆。

解法:用 堆 來解決

  1. 創建一個大小為 k 的堆(大根堆 or 小根堆)
  2. 循環
  • 1.依次進堆
  • 2.判斷堆的大小是否超過 K

在堆的實現,畫圖和代碼分析建堆,堆排序,時間復雜度以及TOP-K問題,對于求第K個最大元素

  • 我們也是將前K個數建個小堆,然后將剩下的N-K個元素和堆頂元素做比較
  • 如果大于堆頂元素,就先把棧頂元素pop掉,也就是把堆中最小元素刪除,然后將它放進去。
  • 這樣一直循環,直到所有元素都比較完成。

因為是一直把堆中最小的pop掉,那堆的元素就是N個元素中最大的,而堆頂就是第K個最大的元素

別忘記我們這是一個小堆!

  • sum: eg. TOP_K 大,建一個 K 小堆,大于 top 就 pop,push, 最后的就是第 K 大了,因為是一個 數值為 K 的小堆

這里我們也是建小堆,依次進堆,當堆大小超過K個,pop堆頂元素,把堆中最小元素pop掉,并且使堆保持K個大小。

每次都是堆中最小元素去掉。那最后堆中剩下的就是前K個最大元素,而堆頂就是第K個最大元素。

考慮一下下面兩個問題

  • 用大根堆還是小根堆
  • 為什么要用大根堆(小根堆)
class KthLargest {
public:priority_queue<int,vector<int>,greater<int>> heap;int _k;KthLargest(int k, vector<int>& nums) {//第k大,建小堆_k=k;for(auto& num:nums){heap.push(num);if(heap.size()>k) heap.pop();//刪除最小的}}int add(int val) {heap.push(val);if(heap.size()>_k) heap.pop();//刪除最小的return heap.top();}
};

3.前K個高頻單詞

鏈接:692. 前K個高頻單詞

給定一個單詞列表 words 和一個整數 k ,返回前 k 個出現次數最多的單詞。

返回的答案應該按單詞出現頻率由高到低排序。如果不同的單詞有相同出現頻率, 按字典順序 排序。

示例 1:

輸入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
輸出: ["i", "love"]
解析: "i" 和 "love" 為出現次數最多的兩個單詞,均為2次。注意,按字母順序 "i" 在 "love" 之前。

示例 2:

輸入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
輸出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出現次數最多的四個單詞,出現次數依次為 4, 3, 2 和 1 次。

題解

這是一個TopK的問題,注意,返回的答案應該按單詞出現頻率由高到低排序。

如果不同的單詞有相同出現頻率, 按字典順序(由低向高) 排序。

解法:利用 “堆” 來解決 TopK 問題

  • 1. 預處理一下原始的字符串數組: 用一個哈希表,統計一下每一個單詞出現的頻次。

  • 2. 創建一個大小為 k 的堆,類提供的比較函數滿足不了要求,我們要自己定義一個!

(返回的答案應該按單詞出現頻率由高到低排序。如果不同的單詞有相同出現頻率, 按字典順序(由低向高) 排序。)

如果比較頻次創建一個小根堆,如果比較字典序(頻次相同的時候),創建一個大根堆。

所以說創建堆寫比較函數的時候必須要考慮這兩點

  • 當頻次相同的時候字典序按照大根堆方式比較
  • 當頻次不同的時候按照小根堆方式比較。

  • 3. 循環

1.依次進堆

2.判斷堆的大小是否超過 K

  • 4. 提取結果
  • 因為求前K大,所以建的是一個小根堆,然后提取堆頂元素在pop是一個升序的。
  • 逆序一下取前K個

代碼

#和 ds 討論后的優化代碼,用lambda和emplace

?4.數據流的中位數

鏈接:295. 數據流的中位數

中位數是有序整數列表中的中間值。如果列表的大小是偶數,則沒有中間值,中位數是兩個中間值的平均值。

  • 例如 arr = [2,3,4] 的中位數是 3
  • 例如 arr = [2,3] 的中位數是 (2 + 3) / 2 = 2.5

實現 MedianFinder 類:

  • MedianFinder() 初始化 MedianFinder 對象。
  • void addNum(int num) 將數據流中的整數 num 添加到數據結構中。
  • double findMedian() 返回到目前為止所有元素的中位數。與實際答案相差 10-5 以內的答案將被接受。

示例 1:

輸入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
輸出
[null, null, null, 1.5, null, 2.0]解釋
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

題解

給一個數據流,讓返回每次當前已經加入到數組的數據流的中位數。

中位數是有序整數列表中的中間值。

  • 如果列表的大小是偶數,則沒有中間值,中位數是兩個中間值的平均值。
  • 表的大小是奇數,直接返回中間的數。

解法一:直接sort

每次從數據流中來一個數插入數組中之后,都對當前數組進行sort

然后通過下標的方式找到中間數。

每次add加入一個數都要sort,時間復雜度是O(nlogn)。

  • 總體時間復雜度是非常恐怖的。
  • 因為是下標訪問,find 時間復雜度是 O(1)

解法二:插入排序的思想

[0,end] 有序,插入 end + 1,使 [0, end + 1]有序。

這道題正好就是這樣的思想。

相當于打撲克,找到合適的位置。

add函數,每次插入一個數的時候都需要從后往前掃描找一個插入的位置

  • 因此時間復雜度是O(n)
  • find 也是通過下標去找 時間復雜度是O(1)

解法三:大小堆來維護數據流的中位數

此時有一個數軸已經按照從小到大的排好序了,這個時候想找中間數的時候。

  • 把這些數的前半部分放到一個大根堆里面,后半部分放到小根堆里面。
  • 此時找中間值也很快,前面較小的數放到大根堆里面,堆頂元素是數軸中這些較小元素種最右邊的值。
  • 后面較大的數放到小根堆里面,堆頂元素是數軸中這些較大元素最左邊。

此時我們僅需根據數組中的元素的個數就可以求出中位數是多少了。

如果數組是偶數

  • 大根堆和小根堆正好把數軸平分
  • 然后 大堆堆頂元素和小堆堆頂元素相加 /2就是這個數組的中位數。

如果數組是奇數個。

  • 我們就先人為規定一下,數軸左邊元素是m個,右邊是n個
  • 人為規定左邊大根堆多方一個元素,m > n (m = n + 1)
  • 此時中位數就是 左邊大根堆的堆頂元素。

向這樣用大根堆存左邊較小部分,小根堆存右邊較大部分。

  • find 時間復雜度也是O(1),而add快了很多
  • 因為我們是從堆存這些元素的,插入和刪除每次調整堆僅需O(logn)

細節問題:

add如何實現:

  • 假設現在有兩個堆了。
  • 一個大根堆left,一個小根堆right。
  • left元素個數m個,right元素個數n個,left堆頂元素x,right堆定元素y。

如果此時來了一個數num,num要么放在left里,要么放在right里。

但是放好之后可能會破壞之前的規則:

  • m == n
  • m > n —> m == n + 1

我們必須維護上面的規則,才能正確找到數組中位數。

接下來分情況討論:

m == n

  • num要么插入left,要么插入right。
  • 如果num要進入left,那么num <= x,但是別忘記 m == n 有可能兩個堆全為空,num也是直接進入left。
  • 此時 m 比 n 多了一個。沒關系直接進就行。

如果num進入right,那條件是 num > x。

  • 此時就有問題了。n > m了,而 n > m是不被允許的,所以我們要把右邊堆調整一下,就是拿right堆頂元素放到left里。
  • 因為right是一個小根堆,堆頂就是最小值。
  • 拿到left,還是能保證left堆里元素是較小的,right堆里元素是較大的。
  • 拿right堆頂元素放到left里正好滿足 m == n + 1。

這里有一個細節問題,必須num先進right堆,然后再拿right堆定元素放到left

因為 x < num < y,如果直接把y拿過去了,就破壞了left都是較小元素。right都是較大元素。

m > n —> m == n + 1

如果num進入left,那么num <= x , 但是此時不滿足 m == n + 1

  • 因此 進棧后將棧頂元素給right。
  • 如果num進入right,那么num > x , m == n了,直接進就行了

注意: 上面都是 先進棧 再拿棧頂移動

順便復習了大頂堆小頂堆,紅黑樹,avl樹,排序。很好的題

class MedianFinder {
private:std::priority_queue<int> left;    // 大頂堆存較小的一半std::priority_queue<int, std::vector<int>, std::greater<int>> right; // 小頂堆存較大的一半public:MedianFinder() {}  // 構造函數不需要初始化隊列void addNum(int num) {int m=left.size();int n=right.size();if(m==n){if(m==0 || num<=left.top())//注意為空left.push(num);else{right.push(num);left.push(right.top());right.pop();}}if(m>n){if(num<=left.top()){left.push(num);right.push(left.top());left.pop();}//先 進棧 再拿棧頂移動elseright.push(num);}}double findMedian() {if(left.size() > right.size()) {return left.top();}return (left.top() + right.top()) / 2.0;  // 2.0確保浮點運算}
};

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

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

相關文章

XSS漏洞靶場---(復現)

XSS漏洞靶場—&#xff08;復現&#xff09; 反射型 XSS 的特點是攻擊者誘導用戶點擊包含惡意腳本的 URL&#xff0c;服務器接收到請求后將惡意腳本反射回響應頁面&#xff0c;瀏覽器執行該腳本從而造成攻擊&#xff0c;惡意腳本不會在服務器端存儲。 Level 1(反射型XSS) 此漏…

2025/3.17 郭院安排會議與南京銀行參訪

目錄 *郭院會議&#xff1a;服務外包*1.會遇到的問題以及解決方案2.考慮行業目前會碰到的瓶頸3.后端應該呈現處理圖像的過程4.記得做報告、文檔說明和視頻等工作 *南京銀行&#xff08;鑫合易家&#xff09;參訪記錄*1. 風險評分業務流程筆記![在這里插入圖片描述](https://i-b…

Cloud Ace 宣布成為 Langfuse 亞太地區首個代理商,提供 LLM 全鏈路解決方案

Cloud Ace 宣布正式代理 Langfuse 產品&#xff0c;是 Langfuse 在亞太地區唯一的官方授權經銷商&#xff0c;全面負責其商用許可證的銷售、部署與技術支持服務。通過此次合作&#xff0c;Cloud Ace 將充分發揮 Langfuse 的先進技術能力與行業專業知識&#xff0c;為企業級客戶…

Helm 的倉庫管理與 Chart 搜索

在使用 Helm 管理 Kubernetes 應用的過程中&#xff0c;倉庫管理與 Chart 搜索是兩個核心功能。通過 Helm 倉庫&#xff0c;用戶可以方便地存儲、分享和獲取 Helm Chart&#xff0c;而搜索功能則幫助用戶快速找到所需的 Chart。本文將詳細介紹 Helm 倉庫的概念、管理方法以及如…

Matlab 汽車振動多自由度非線性懸掛系統和參數研究

1、內容簡介 略 Matlab 169-汽車振動多自由度非線性懸掛系統和參數研究 可以交流、咨詢、答疑 2、內容說明 略 第二章 汽車模型建立 2.1 汽車懸架系統概述 2.1.1 懸架系統的結構和功能 2.1.2 懸架分類 2.2 四分之一車輛模型 對于車輛動力學&#xff0c;一般都是研究其懸…

免訓練指標(Zero-Cost Proxies)

1. 什么是免訓練指標&#xff08;Zero-Cost Proxies&#xff0c;ZC proxies&#xff09;&#xff1f; 免訓練指標是一類 無需完整訓練模型即可評估其性能的度量方法&#xff0c;主要用于提高 神經架構搜索&#xff08;NAS&#xff09; 的效率。 傳統 NAS 需要訓練候選架構來評…

C語言 —— 此去經年夢浪蕩魂音 - 深入理解指針(卷二)

目錄 1. 數組名與地址 2. 指針訪問數組 3.一維數組傳參本質 4.二級指針 5. 指針數組 6. 指針數組模擬二維數組 1. 數組名與地址 我們先看下面這個代碼&#xff1a; int arr[10] { 1,2,3,4,5,6,7,8,9,10 };int* p &arr[0]; 這里我們使用 &arr[0] 的方式拿到了數…

基于Python pyscard庫采集ACS ACR122U NFC讀卡器數據的詳細操作步驟

步驟1&#xff1a;安裝驅動 1. 下載驅動&#xff1a; - 訪問ACS官網的驅動下載頁面&#xff1a;[ACR122U驅動下載](https://www.acs.com.hk/en/drivers/6/acr122u-nfc-reader/)。 - 選擇適用于Windows的驅動&#xff08;如 ACR122U Driver (Windows) V3.05.02.zip&#xff09;…

深度學習 Deep Learning 第1章 深度學習簡介

第1章 深度學習簡介 概述 本章介紹人工智能&#xff08;AI&#xff09;和深度學習領域&#xff0c;討論其歷史發展、關鍵概念和應用。解釋深度學習如何從早期的AI和機器學習方法演變而來&#xff0c;以及如何有效解決之前方法無法應對的挑戰。 關鍵概念 1. 人工智能的演變 …

python實現簡單的圖片去水印工具

python實現簡單的圖片去水印工具 使用說明&#xff1a; 點擊"打開圖片"選擇需要處理的圖片 在圖片上拖拽鼠標選擇水印區域&#xff08;紅色矩形框&#xff09; 點擊"去除水印"執行處理 點擊"保存結果"保存處理后的圖片 運行效果 先簡要說明…

軟件功能性測試有哪些步驟和挑戰?軟件測評服務機構分享

軟件功能性測試是對軟件系統進行驗證的一種基本方法。其主要目標是確保軟件系統能夠按照預期的要求和功能進行操作。從用戶的角度看&#xff0c;功能性測試旨在檢查軟件是否實現了所有要求的功能&#xff0c;保證用戶體驗的順暢與滿意。 一、軟件功能性測試的測試步驟   1、…

《C#上位機開發從門外到門內》3-4:基于TCP/IP的遠程監控系統設計與實現

文章目錄 一、項目概述二、系統架構設計三、通信協議設計四、功能模塊實現五、系統安全性與穩定性六、性能優化與測試七、實際應用案例八、結論 隨著信息技術的飛速發展&#xff0c;遠程監控系統在工業自動化、智能家居、環境監測等領域的應用日益廣泛。基于TCP/IP協議的遠程監…

在react當中利用IntersectionObserve實現下拉加載數據

目錄 一、傳統的下拉加載方案 二、存在問題 1.性能較差 2.不夠精確 三、IntersectionObserve版本下拉加載 1、callback 2、options 四、IntersectionObserver實例 1、Intersection的優勢 2、實現思路 3、代碼實現 在進行前端開發的過程中&#xff0c;常常會碰到下拉…

深入理解C++編程:從內存管理到多態與算法實現

C 是一門功能強大的編程語言&#xff0c;廣泛應用于系統編程、游戲開發和高性能計算等領域。本文將通過一系列經典問題&#xff0c;深入探討 C 的核心知識點&#xff0c;包括內存管理、多態&#xff08;結合函數重載與覆蓋&#xff09;、多線程、TCP/IP 模型、軟鏈接與硬鏈接的…

相對論之光速

然而&#xff0c;基礎物理學的進步很少全部由實驗取得。為了解實驗結果背后的機制&#xff0c;法拉第問道&#xff0c;既然磁鐵沒有接觸導線&#xff0c;導線中怎么會產生電流?一股電流又怎么能使指南針指針發生偏轉?有某種作用因素必然在磁鐵、導線和指南針之間的空隙中傳遞…

文本檢測-文本內容審核-文本過濾接口如何用PHP調用?

一、什么是文本檢測接口呢&#xff1f; 文本內容審核過濾&#xff0c;提供對敏感事件、違規詞語及監管要求封禁詞語的識別審核能力&#xff0c;包含海量歷史數據&#xff0c;有效過濾違禁違規、惡意推廣、低俗辱罵、低質灌水、廣告法審核&#xff0c;該接口應用場景廣泛&#…

突破極限:獵板PCB在HDI盲埋孔樹脂塞孔工藝中的創新與挑戰

在高端電子制造領域&#xff0c;HDI&#xff08;高密度互連&#xff09;技術憑借其高精度、高可靠性的特點&#xff0c;已成為5G通信、航空航天、智能汽車等領域的核心技術支撐。作為HDI板制造的核心環節&#xff0c;盲埋孔樹脂塞孔工藝直接決定了電路板的信號完整性、散熱性能…

群體智能優化算法-?魚優化算法 (Remora Optimization Algorithm, ROA,含Matlab源代碼)

摘要 ?魚優化算法&#xff08;Remora Optimization Algorithm&#xff0c;ROA&#xff09;是一種基于?魚在海洋中寄生與捕食者間交互關系而提出的元啟發式算法。通過模擬?魚在宿主附近進行寄生、吸附和隨機機動等行為&#xff0c;ROA 在全局與局部搜索之間取得平衡。本文提…

【數學建模】一致矩陣的應用及其在層次分析法(AHP)中的性質

一致矩陣在層次分析法(AHP)中的應用與性質 在層次分析法(AHP)中&#xff0c;一致矩陣是判斷矩陣的一種理想狀態&#xff0c;它反映了決策者判斷的完全合理性和一致性&#xff0c;也就是為了避免決策者認為“A比B重要&#xff0c;B比C重要&#xff0c;但是C又比A重要”的矛盾。…

DeepSeek R1 與 ktransformers:結合蘋果 M4 Mac 的 LLM 推理深度分析

引言 大型語言模型&#xff08;LLM&#xff09;的快速發展為人工智能領域帶來了革命性變化。DeepSeek R1 和 ktransformers 代表了軟件層面的最新突破&#xff0c;而蘋果在 2025 年 3 月 12 日發布的 M4 Mac 系列則提供了硬件支持。本文將深入分析這些技術的交匯點&#xff0c…