【高頻面試題】數組中的第K個最大元素(堆、快排進階)

文章目錄

    • 數組中的第K個最大元素
      • 題目描述
      • 示例1
      • 示例2
      • 提示:
    • 解法1(堆維護前k大元素)
    • 解法2 手寫堆維護
    • 解法3(快速選擇算法)
    • 例題:P1923 【深基9.例4】求第 k 小的數
    • 參考

數組中的第K個最大元素

題目描述

給定整數數組 n u m s nums nums和整數 k k k,請返回數組中第 k k k 個最大的元素。
請注意,你需要找的是數組排序后的第 k k k 個最大的元素,而不是第 k k k 個不同的元素。
你必須設計并實現時間復雜度為 O ( n ) O(n) O(n)的算法解決此問題。

示例1

輸入: [3,2,1,5,6,4], k = 2
輸出: 5

示例2

輸入: [3,2,3,1,2,4,5,5,6], k = 4
輸出: 4

提示:

  • 1 < = k < = n u m s . l e n g t h < = 10 5 1 <= k <= nums.length <= 10^5 1<=k<=nums.length<=105
  • ? 10 4 < = n u m s [ i ] < = 10 4 -10^4 <= nums[i] <= 10^4 ?104<=nums[i]<=104

解法1(堆維護前k大元素)

時間復雜度 O ( n l o g k ) O(nlogk) Onlogk 空間復雜度 O ( k ) O(k) Ok)

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, greater<int>> pq; for(auto& num: nums){pq.emplace(num);if(pq.size() > k){pq.pop();   // 堆中元素超過k個,彈出最小的那個}}return pq.top();   }
};

解法2 手寫堆維護

思路:

  • n u m s nums nums種存放二叉堆,索引 [ 0 , n ? 1 ] [0,n - 1] [0,n?1]對應按層序遍歷對應的元素,對于下標從0開始的某節點 i i i,左右孩子節點編號分別為 i ? 2 + 1 , i ? 2 + 2 i*2+1,i*2+2 i?2+1,i?2+2
  • 下沉操作: m a x H e a p i f y maxHeapify maxHeapify操作為將二叉堆數組 n u m s nums nums索引 i i i處元素下沉
  • 建堆操作:我們從最后一個非葉子節點 h e a p S i z e / 2 ? 1 heapSize / 2-1 heapSize/2?1開始倒序遍歷,從下往上下沉
  • 刪除操作:每次將堆頂交換到數組末尾,再將 h e a p S i z e heapSize heapSize減一,最后再調整新的堆頂即可
  • 時間復雜度 O ( n l o g n ) O(nlogn) Onlogn 空間復雜度 O ( l o g n ) O(logn) Ologn) 因為最大堆需要維護n個結點
class Solution {
public:// down void maxHeapify(vector<int>& a, int i, int heapSize) {int l = i * 2 + 1, r = i * 2 + 2, largest = i;if (l < heapSize && a[l] > a[largest]) {largest = l;}if (r < heapSize && a[r] > a[largest]) {largest = r;}if (largest != i) {swap(a[i], a[largest]);maxHeapify(a, largest, heapSize);}}// initialize void buildMaxHeap(vector<int>& a, int heapSize) {for (int i = heapSize / 2 - 1; i >= 0; i--) {maxHeapify(a, i, heapSize);}}int findKthLargest(vector<int>& nums, int k) {int heapSize = nums.size();buildMaxHeap(nums, heapSize); // 建堆// 執行k-1次提取最大值操作for (int i = nums.size() - 1; i >= nums.size() - k + 1; i--) {swap(nums[0], nums[i]);   // 調整堆頂-- heapSize;              // 刪除堆maxHeapify(nums, 0, heapSize); }return nums[0];}
};

解法3(快速選擇算法)

我們首先來回顧一下快排的實現

void quickSort(vector<int>& nums, int l, int r) {if (l >= r) return;// - i 初始在左邊界左側(l-1)// - j 初始在右邊界右側(r+1)// - 基準值 x 選中間元素(避免極端情況如全排序數組導致最壞時間復雜度)int i = l - 1, j = r + 1;int x = nums[(l + r) >> 1]; // 位運算代替 (l + r) / 2,等價且更高效// partition :雙指針從兩端向中間移動while (i < j) {// 移動左指針 i:跳過所有小于 x 的元素,直到找到 >=x 的元素do i++; while (nums[i] < x); // 移動右指針 j:跳過所有大于 x 的元素,直到找到 <=x 的元素do j--; while (nums[j] > x);//  如果指針未交錯,交換左右指針的元素(確保左邊 <=x,右邊 >=x)if (i < j) swap(nums[i], nums[j]);}// 4. 遞歸排序左右子數組:quickSort(nums, l, j), quickSort(nums, j + 1, r);
}
  • 快速選擇( Q u i c k s e l e c t Quickselect Quickselect)算法是一種用于在未排序的列表中找到第k小(或第k大)元素的高效算法。與快速排序一樣,它使用分治策略,但不同于快速排序的是,它只遞歸處理包含目標元素的那一部分,而不是全部。這使得快速選擇的平均時間復雜度為 O ( n ) O(n) O(n),最壞情況為 O ( n 2 ) O(n^2) O(n2),但在實際應用中,通過隨機化選取樞軸( p i v o t pivot pivot)可以避免最壞情況。
  • 復雜度:遞歸時,每層時間復雜度為 O ( n ) O(n) O(n),但并不是都進入左右兩部分遞歸。僅進入一側遞歸在平均情況下 數組長度會減半,故平均情況下的時間復雜度為 n + n / 2 + n / 4 + … + 1 = O ( n ) n+n/2+n/4+…+1=O(n) n+n/2+n/4++1=O(n)

以下是快速選擇實現找第K大元素的具體實現:

class Solution {
public:int quick_select(vector<int>& nums, int l, int r, int k) {if (l == r) return nums[k];int i = l - 1, j = r + 1, x = nums[l + r >> 1]; // 若選取nums[l], 極端樣例 時間會很久//int x = nums[rand() % (r - l + 1) + l], i = l - 1, j = r + 1; // 隨機選取while (i < j) {do i ++ ; while (nums[i] > x); // 注意是第k大 上面的模板是升序排序do j -- ; while (nums[j] < x);if (i < j) swap(nums[i], nums[j]);}if (k <= j) return quick_select(nums, l, j, k);else return quick_select(nums, j + 1, r, k);}int findKthLargest(vector<int>& nums, int k) {//srand(time(0)); // 隨機種子return quick_select(nums, 0, nums.size() - 1, k - 1); // 0-base}
};

例題:P1923 【深基9.例4】求第 k 小的數

#include <bits/stdc++.h>using namespace std;const int N = 5e6 + 7;int n, k;
int a[N];int quick_select(int nums[], int l, int r, int k) {if (l == r) return nums[k];int x = nums[l], i = l - 1, j = r + 1;while (i < j) {// paration 方向改一下即可do i ++; while (nums[i] < x); do j --; while (nums[j] > x);if (i < j) swap(nums[i], nums[j]);}if (k <= j) return quick_select(nums, l, j, k);else return quick_select(nums, j + 1, r, k);
}int main() {scanf("%d%d", &n, &k);//getchar();for (int i = 0; i < n; i++) {scanf("%d", &a[i]);}printf("%d\n", quick_select(a, 0, n - 1, k));return 0;
}

參考

  • LeetCode官方題解:數組中的第K個最大元素
  • yxc常用代碼模板1——基礎算法
  • LeetCode 215. 數組中的第K個最大元素

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

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

相關文章

『uniapp』添加桌面長按快捷操作 shortcuts(詳細圖文注釋)

目錄 手機環境適配說明安卓效果圖代碼 iOS(暫未實測,沒有水果開發者)總結 歡迎關注 『uniapp』 專欄&#xff0c;持續更新中 歡迎關注 『uniapp』 專欄&#xff0c;持續更新中 手機環境適配說明 個別手機系統可能需要進行特別的權限設置,否則會無法使用 桌面快捷方式: 已知的有…

PHP 垃圾回收高級特性

PHP 垃圾回收高級特性 1. 循環引用與內存泄漏 單純的引用計數在遇到循環引用時會導致內存泄漏&#xff0c;主要原因是引用計數無法正確識別那些僅通過循環引用相互關聯但實際上已經不可達的對象。 1.1 引用計數的基本原理 引用計數是一種內存管理機制&#xff0c;通過維護每…

奈雪小程序任務腳本

功能概述 該腳本用于自動完成奈雪點單小程序的每日任務&#xff0c;包括&#xff1a; 自動檢測 Token 有效性自動簽到&#xff08;如果未簽到&#xff09;獲取用戶基礎信息&#xff08;昵稱、手機號&#xff09;查詢當前奈雪幣余額記錄連續簽到天數支持多賬號執行&#xff0c…

基于cornerstone3D的dicom影像瀏覽器 第二十七章 設置vr相機,復位視圖

文章目錄 前言一、VR視圖設置相機位置1. 相機位置參數2. 修改mprvr.js3. 調用流程1) 修改Toolbar3D.vue2) 修改View3d.vue3) 修改DisplayerArea3D.vue 二、所有視圖復位1.復位流程說明2. 調用流程1) Toolbar3D中添加"復位"按鈕&#xff0c;發送reset事件2) View3d.vu…

Opencv4 c++ 自用筆記 03 滑動條、相機與視頻操作

1. 相機與視頻操作 1.1 打開視頻&#xff0f;相機 OpenCV 中 imread() 只能讀取靜態圖像&#xff0c;若要讀取視頻文件或攝像頭流&#xff0c;需要使用 VideoCapture 類&#xff1a; // 構造函數 cv::VideoCapture::VideoCapture(); cv::VideoCapture…

身份證發給別人怎么加水印?賽文奧特曼身份證添加水印教程

我們經常需要使用身份證照片進行身份驗證、資料提交等操作。然而&#xff0c;直接將身份證照片發送給他人或上傳到網絡存在一定的信息泄露風險。為了更好地保護個人隱私&#xff0c;我們可以使用 簡鹿水印助手 這款工具&#xff0c;在身份證照片上添加專屬水印&#xff0c;從而…

十、【核心功能篇】項目與模塊管理:前端頁面開發與后端 API 聯調實戰

【核心功能篇】項目與模塊管理&#xff1a;前端頁面開發與后端 API 聯調實戰 前言準備工作第一部分&#xff1a;完善項目管理功能 (Project)1. 創建/編輯項目的表單對話框組件 第二部分&#xff1a;模塊管理功能 (集成到項目詳情頁)1. 創建模塊相關的 API 服務 (src/api/module…

ES分詞搜索

ES的使用 前言作者使用的版本作者需求 簡介ES簡略介紹ik分詞器簡介 使用es的直接簡單使用es的查詢 es在java中使用備注說明 前言 作者使用的版本 es: 7.17.27spring-boot-starter-data-elasticsearch: 7.14.2 作者需求 作者接到一個業務需求&#xff0c;我們系統有份數據被…

Axure設計案例——科技感立體柱狀圖

想讓你的數據展示告別平淡無奇&#xff0c;成為吸引全場目光的焦點嗎&#xff1f;快來瞧瞧這個Axure設計的科技感立體柱狀圖案例&#xff01;科技感設計風格借助逼真的立體效果打破傳統柱狀圖的平面感&#xff0c;營造出一種令人眼前一亮的視覺震撼。每一個柱狀體都仿佛是真實存…

惡意npm與VS Code包竊取數據及加密貨幣資產

60個npm包竊取系統敏感信息 安全研究人員在npm軟件包注冊表中發現60個惡意組件&#xff0c;這些組件能夠收集主機名、IP地址、DNS服務器和用戶目錄信息&#xff0c;并將其發送至Discord平臺控制的終端節點。據Socket安全研究員Kirill Boychenko上周發布的報告顯示&#xff0c;…

leetcode 2359. 找到離給定兩個節點最近的節點

給你一個 n 個節點的 有向圖 &#xff0c;節點編號為 0 到 n - 1 &#xff0c;每個節點 至多 有一條出邊。 有向圖用大小為 n 下標從 0 開始的數組 edges 表示&#xff0c;表示節點 i 有一條有向邊指向 edges[i] 。如果節點 i 沒有出邊&#xff0c;那么 edges[i] -1 。 同時…

1. pytorch手寫數字預測

1. pytorch手寫數字預測 1.背景2.準備數據集2.定義模型3.dataloader和訓練4.訓練模型5.測試模型6.保存模型 1.背景 因為自身的研究方向是多模態目標跟蹤&#xff0c;突然對其他的視覺方向產生了興趣&#xff0c;所以心血來潮的回到最經典的視覺任務手寫數字預測上來&#xff0…

AWS WebRTC:獲取ICE服務地址(part 2): ICE Agent的作用

上一篇&#xff0c;已經獲取到了ICE服務地址&#xff0c;從返回結果中看&#xff0c;是兩組TURN服務地址。 拿到這些地址有什么用呢&#xff1f;接下來就要說到WebRTC中ICE Agent的作用了&#xff0c;返回的服務地址會傳給WebRTC最終給到ICE Agent。 ICE Agent的作用&#xf…

大數據時代的利劍:Bright Data網頁抓取與自動化工具共建高效數據采集新生態

目錄 一、為何要選用Bright Data網頁自動化抓取——幫助我們高效高質解決以下問題&#xff01; 二、Bright Data網頁抓取工具 - 網頁爬蟲工具實測 2.1 首先注冊用戶 2.2 首先點擊 Proxies & Scraping &#xff0c;再點擊瀏覽器API的開始使用 2.3 填寫通道名稱&#xff…

指紋識別+精準化POC攻擊

開發目的 解決漏洞掃描器的痛點 第一就是掃描量太大&#xff0c;對一個站點掃描了大量的無用 POC&#xff0c;浪費時間 指紋識別后還需要根據對應的指紋去進行 payload 掃描&#xff0c;非常的麻煩 開發思路 我們的思路分為大體分為指紋POC掃描 所以思路大概從這幾個方面…

【Day40】

DAY 40 訓練和測試的規范寫法 知識點回顧&#xff1a; 彩色和灰度圖片測試和訓練的規范寫法&#xff1a;封裝在函數中展平操作&#xff1a;除第一個維度batchsize外全部展平dropout操作&#xff1a;訓練階段隨機丟棄神經元&#xff0c;測試階段eval模式關閉dropout 作業&#x…

【HTML-13】HTML表格合并技術詳解:打造專業數據展示

表格是HTML中展示結構化數據的重要元素&#xff0c;而表格合并則是提升表格表現力的關鍵技術。本文將全面介紹HTML中的表格合并方法&#xff0c;幫助您創建更專業、更靈活的數據展示界面。 1. 表格合并基礎概念 在HTML中&#xff0c;表格合并主要通過兩個屬性實現&#xff1a…

<uniapp><threejs>在uniapp中,怎么使用threejs來顯示3D圖形?

前言 本專欄是基于uniapp實現手機端各種小功能的程序,并且基于各種通訊協議如http、websocekt等,實現手機端作為客戶端(或者是手持機、PDA等),與服務端進行數據通訊的實例開發。 發文平臺 CSDN 環境配置 系統:windows 平臺:visual studio code、HBuilderX(uniapp開…

如何制作全景VR圖?

全景VR圖&#xff0c;特別是720度全景VR&#xff0c;為觀眾提供一種沉浸式體驗。 全景VR圖能夠捕捉場景的全貌&#xff0c;還能將多個角度的圖片或視頻無縫拼接成一個完整的全景視角&#xff0c;讓觀眾在虛擬環境中自由探索。隨著虛擬現實&#xff08;VR&#xff09;技術的飛速…

前端使用qrcode來生成二維碼的時候中間添加logo圖標

這個開源倉庫可以讓你在前端頁面中生成二維碼圖片&#xff0c;并且支持調整前景色和背景色&#xff0c;但是有個問題&#xff0c;就是不能添加logo圖片。issue&#xff1a; GitHub Where software is built 但是已經有解決方案了&#xff1a; add a logo picture Issue #21…