【算法與數據結構】單調隊列

目錄

單調隊列

使用單調隊列維護滑動窗口

具體過程:

代碼實現:?

復雜度分析:

使用單調隊列優化動態規劃

例題?


單調隊列

單調隊列(deque)是一種特殊的隊列,隊列中的元素始終嚴格遞增或者遞減排列。這樣就可以保證隊頭元素始終是最大值或者最小值。

【問題引入】

有一個數組,長度為n,給你一個區間[left,right],求出該區間內的最小值或者最大值。

我們如果進行普通的遍歷,最壞的情況下時間復雜度是O(N),遍歷整個數組。

而我們如果用單調隊列來維護這段區間,始終保持隊列的單調性,就可以在O(1)的時間內找到該區間的最大值或者最小值,就是隊頭元素

【結論】

所以單調隊列的核心用途是高效維護動態窗口的極值(最大值或最小值)。

那么對于一些動態規劃,如轉移方程需要進行一段區間的最值計算,可以使用單調隊列優化。


使用單調隊列維護滑動窗口

題目鏈接:239. 滑動窗口最大值 - 力扣(LeetCode)

當窗口形成后,我們需要找到這段窗口中的最大值,暴力的方法就是對這段區間進行遍歷,每個元素進行比較,選出最大值。這樣做時間復雜度為O(N^2),效率太低。

使用單調隊列優化:單調隊列維護該窗口,隊頭元素為最大元素。時間復雜度為O(N)。

具體過程:

  • 創建一個單調對列,維護該隊列的遞減性,以保證對頭元素為窗口中的最小值
  • 對于該單調隊列,存放元素的下標,按值遞減排列。新來一個元素(也就是滑動窗口右移一步),需要判斷對頭元素是否還在窗口內,所以記錄下標,便于判斷對頭元素是否還在窗口中,如果不在,刪除對頭元素。
  • 新來一個元素(也就是滑動窗口右移一步),每次都需要比較隊尾元素與當前元素的大小,我們維護的是遞減隊列,如果隊尾元素大于當前元素,則將當前元素的下標直接加入隊列;如果隊尾元素小于當前元素,則將隊尾元素刪除,直到隊尾元素大于當前元素,再將當前元素下標加入隊列,保持隊列的遞減性。
  • 窗口形成后,統計結果即可。隊頭元素就是最大元素。

代碼實現:?

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {//雙端隊列 存儲數組索引deque<int> dq;vector<int> res;for(int i=0;i<nums.size();i++){//移除超出范圍的隊首元素while(!dq.empty()&&dq.front()<=i-k)dq.pop_front();//維護隊列遞減性(從隊頭到隊尾),移除所有小于當前元素的隊尾元素 while(!dq.empty()&&nums[dq.back()]<nums[i])dq.pop_back();//當前元素入隊列dq.push_back(i);//窗口形成后,統計結果,隊頭元素就是最大元素if(i>=k-1)res.push_back(nums[dq.front()]);}return res;}
};

?上面的寫法是使用庫中的deque,還可以使用數組來模擬:


#include<iostream>
using namespace std;
const int N = 1e6 + 5;int a[N], q[N];
int n, k;int main()
{cin >> n >> k;for (int i = 1; i <= n; i++) cin >> a[i];int hh = 0, tt = -1;for (int i = 1; i <= n; i++){while (hh <= tt && i - k >= q[hh]) hh++;//處理隊首while (hh <= tt && a[q[tt]] <= a[i]) tt--;//處理隊尾q[++tt] = i;//隊尾元素加入if (i >= k) cout << a[q[hh]] << " ";//輸出隊首元素}cout << endl;return 0;
}

復雜度分析:

每個元素最多入隊和出隊一次,時間復雜度為O(N),隊列最多存儲k個元素,時間復雜度為O(K)。?


使用單調隊列優化動態規劃

在動態規劃中,當狀態轉移需要在一個窗口查找極值時,可以使用單調隊列優化時間復雜度。

題目鏈接:P5858 「SWTR-3」Golden Sword - 洛谷

狀態表示:dp[i][j]表示加入第i個材料時,?鍋內的材料個數為j(包括此時加入的),此時的耐久度的最大值。

狀態轉移方程的分析:加入第i個材料后的最大耐久度,等于加入第i-1個材料時最大的耐久度,再加上自身的耐久度,也就是再加上a[i]*j。

狀態轉移方程:dp[i][j]=max(dp[i][j],dp[i-1][k]+j*a[i]),j-1<=k<=min(w,j-1+s)。

正常使用動態規劃:

第一層循環遍歷i。

第二層循環遍歷j,填寫dp[i][j]。

但是由于有求[j-1,min(w,j-1+s)]最大值的操作,所以還需一層循環求最大值。

共三層循環,時間復雜度太大,需要進行優化。

#include <iostream>
using namespace std;
long long n, m, s;
long long a[5505];
long long dp[5505][5505];int main()
{cin >> n >> w >> s;for (long long i = 1; i <= n; i++)cin >> a[i];for (long long i = 0; i <= n; i++)for (long long j = 0; j <= w; j++)dp[i][j] = -1e18;dp[0][0] = 0;//dp[i][j]選第i個材料時,此時正好j個材料的最大耐久度for (long long i = 1; i <= n; i++)for (long long j = 1; j <= w; j++)for (long long k = j - 1; k <= min(w, s + j - 1); k++)dp[i][j] = max(dp[i][j], dp[i-1][k] + a[i] * j);long long ans = -1e18;for (int i = 0; i <= w; i++)ans = max(ans, dp[n][i]);cout << ans << endl;return 0;
}

使用單調隊列優化后

在第三層的遍歷,求區間[j-1,min(w,j-1+s)]的最大值,可以使用單調隊列優化,降低時間復雜度。

//單調隊列優化
#include <iostream>
#include <deque>
using namespace std;
long long n, w, s;
long long a[5505];
long long dp[5505][5505];int main()
{cin >> n >> w >> s;for (long long i = 1; i <= n; i++)cin >> a[i];for (long long i = 0; i <= n; i++)for (long long j = 0; j <= w; j++)dp[i][j] = -1e18;dp[0][0] = 0;//dp[i][j]選第i個材料時,此時正好j個材料的最大耐久度for (long long i = 1; i <= n; i++){deque<long long> q;  //單調隊列,記錄區間最大值  存儲索引q.push_back(w);      //下面循環中w不會進隊列,需提前進隊列//[j-1,min(j-1+s,w)]//從右向左遍歷,因為左端點固定,而右端點使用了minfor (long long j = w; j >= 1; j--){//[j-1,min(j-1+s,w)]while (!q.empty() && q.front() > min(w, s + j - 1))q.pop_front();while (!q.empty() && dp[i - 1][q.back()] < dp[i - 1][j-1])q.pop_back();q.push_back(j-1); //比較的是q.back()和j-1位置//統計結果dp[i][j] = a[i] * j + dp[i - 1][q.front()];}}long long ans = -1e18;for (int i = 0; i <= w; i++)ans = max(ans, dp[n][i]);cout << ans << endl;return 0;
}

例題?

題目鏈接:1438. 絕對差不超過限制的最長連續子數組 - 力扣(LeetCode)?

?使用兩個單調隊列來維護窗口的最大值和最小值,結合遞增隊列和遞減隊列。當最大值減最小值超出給定的limit時,窗口的左邊界右移動,直到找到符合的位置,統計結果。

class Solution {
public:int longestSubarray(vector<int>& nums, int limit) {//單調隊列,維護當前窗口的最大值和最小值deque<int> queMax,queMin;int n=nums.size();int left=0,right=0,ret=0;while(right<n){//維護隊列的單調性//遞減while(!queMax.empty()&&queMax.back()<nums[right])queMax.pop_back();//遞增while(!queMin.empty()&&queMin.back()>nums[right])queMin.pop_back();//入隊列元素queMin.push_back(nums[right]);queMax.push_back(nums[right]);while(!queMin.empty()&&!queMax.empty()&&queMax.front()-queMin.front()>limit){if(nums[left]==queMin.front())queMin.pop_front();if(nums[left]==queMax.front())queMax.pop_front();left++;}ret=max(ret,right-left+1);right++;}return ret;}
};

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

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

相關文章

AutoGen 技術博客系列 九:從 v0.2 到 v0.4 的遷移指南

本系列博文在掘金同步發布, 更多優質文章&#xff0c;請關注本人掘金賬號&#xff1a; 人肉推土機的掘金賬號 AutoGen系列一&#xff1a;基礎介紹與入門教程 AutoGen系列二&#xff1a;深入自定義智能體 AutoGen系列三&#xff1a;內置智能體的應用與實戰 AutoGen系列四&am…

深度學習每周學習總結Y1(Yolov5 調用官方權重進行檢測 )

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客Y1中的內容 &#x1f356; 原作者&#xff1a;K同學啊 | 接輔導、項目定制 ** 注意該訓練營出現故意不退押金&#xff0c;惡意揣測偷懶用假的結果冒充真實打卡記錄&#xff0c;在提出能夠拿到視頻錄像…

為AI聊天工具添加一個知識系統 之117 詳細設計之58 思維導圖及觀察者效應 之2 概念全景圖

&#xff08;說明&#xff1a;本文和上一篇問題基本相同&#xff0c;但換了一個模型 deepseek-r1&#xff09; Q1227、在提出項目“為使用AI聊天工具的聊天者加掛一個專屬的知識系統”后&#xff0c;我們已經進行了了大量的討論-持續了近三個月了。這些討論整體淋漓盡致體現了…

2012年IMO幾何預選題第6題

設有非等腰的 △ A B C \triangle ABC △ABC, O O O 和 I I I 分別為外心和內心. 在邊 A C AC AC, A B AB AB 上分別存在兩點 E E E 和 F F F, 使得 C D C E A B CDCEAB CDCEAB, B F B D A C BFBDAC BFBDAC. 設 ( B D F ) (BDF) (BDF) 和 ( C D E ) (CDE) (CDE)…

為Eclipse IDE安裝插件IBM編程助手watsonx Code Assistant

從Eclipse IDE 安裝 從Eclipse IDE 安裝插件&#xff1a; _1、在Eclipse IDE 中&#xff0c;單擊幫助菜單&#xff0c;然后選擇EclipseMarketplace。 _2、根據您計劃進行的工作類型選擇安裝方式&#xff1a; 有關代碼建議、代碼解釋、代碼文檔和單元測試的集成生成式人工智能&a…

Linux基本指令(三)+ 權限

文章目錄 基本指令grep打包和壓縮zip/unzipLinux和windows壓縮包互傳tar&#xff08;重要&#xff09;Linux和Linux壓縮包互傳 bcuname -r常用的熱鍵關機外殼程序 知識點打包和壓縮 Linux中的權限用戶權限 基本指令 grep 1. grep可以過濾文本行 2. 把包含9的文本行過濾出來了 …

【部署優化篇十四】【十萬字全景拆解:GitHub Actions自動化流水線設計圣經(DeepSeek工業級實踐大公開)】

一、從手工作坊到智能工廠:CI/CD的革命之路 想象一下,你所在的公司每天要手工組裝1000臺手機,每個環節都靠老師傅肉眼檢查——這就是沒有CI/CD的軟件開發現狀。GitHub Actions的出現,就像給軟件交付裝上了特斯拉的超級工廠流水線。 DeepSeek的CI/CD演進史就是一部血淚史:…

“死”循環(查漏補缺)

以下代碼會死循環&#xff1a; #include<iostream> using namespace std; int n,res; int main(){cin>>n;for(int i1;i<n;i){int xi;while(i){int ti%10;i/10;if(t2||t0||t1||t9){resx;break;}}}cout<<res<<endl;return 0; } 你的代碼中存在一個邏…

力扣LeetCode: 2506 統計相似字符串對的數目

題目&#xff1a; 給你一個下標從 0 開始的字符串數組 words 。 如果兩個字符串由相同的字符組成&#xff0c;則認為這兩個字符串 相似 。 例如&#xff0c;"abca" 和 "cba" 相似&#xff0c;因為它們都由字符 a、b、c 組成。然而&#xff0c;"aba…

關于Java 反射的簡單易懂的介紹

目錄 #0.總覽 #1. 類的反射 ①介紹 ②獲取 ③作用 獲取構造函數&#xff1a; 創建實例&#xff1a; 字段操作&#xff1a; 方法操作&#xff1a; 獲取修飾符&#xff1a; #2.總結 #0.總覽 反射&#xff0c;官方是這樣介紹它的&#xff1a; Reflection is a …

【精調】LLaMA-Factory 快速開始1: Meta-Llama-3.1-8B-Instruct

llamafactory-cli train examples/train_lora/llama3_lora_sft.yaml llamafactory-cli chat examples/inference/llama3_lora_sft.yaml llamafactory-cli export examples/merge_lora/llama3_lora_sft.yaml模型下載 git clone https://www.modelscope.cn/LLM-Research/Meta-Lla…

【07】區塊鏈性能

7-1 基礎性能優化 7-1-1 區塊鏈性能瓶頸 總述 區塊鏈性能指標 區塊鏈的性能指標主要包括&#xff1a; 吞吐量&#xff1a;在固定時間內處理的交易數量 延時&#xff1a;對交易的響應和處理時間 主流區塊鏈與中心化平臺TPS對比 區塊鏈與傳統計算的對比 區塊鏈可信且中立…

安全面試2

文章目錄 簡單描述一下什么是水平越權&#xff0c;什么是垂直越權&#xff0c;我要發現這兩類漏洞&#xff0c;那我代碼審計要注意什么地方水平越權&#xff1a;垂直越權&#xff1a;水平越權漏洞的審計重點垂直越權漏洞的審計重點 解釋一下ssrf漏洞原理攻擊場景修復方法 橫向移…

【Linux 專欄】echo命令實驗

風123456789&#xff5e;-CSDN博客 最近文章閱讀排行榜 【爬蟲基礎】第一部分 網絡通訊 P1/3-CSDN博客 【爬蟲基礎】第一部分 網絡通訊-Socket套接字 P2/3-CSDN博客 【Linux專欄】find命令同步 實驗-CSDN博客 【Linux運維】非root用戶的單向免密登錄_linux 單向免密-CSDN博客…

RTSP協議全解析

RTSP&#xff08;Real Time Streaming Protocol&#xff09;協議全解析 一、協議概述 定位&#xff1a;應用層協議&#xff0c;用于控制流媒體服務器&#xff08;播放、暫停、錄制&#xff09;&#xff0c;媒體傳輸由 RTP/RTCP 實現。 特點&#xff1a; 基于文本&#xff08;…

第15屆 藍橋杯 C++編程青少組中/高級選拔賽 202401 真題答案及解析

第 1 題 【 單選題 】 表達式117 % 16 的結果是( )。 A:0 B:5 C:7 D:10 解析: % 是取模運算符,用于計算兩個數相除后的余數。 計算 117 / 16,結果是 7,余數是 5。因此,117 % 16 = 5。答案: B 第 2 題 【 單選題 】 下列選項中,字符數組定義正確的是( …

qt5實現表盤的旋轉效果,通過提升QLabel類

因為工作需要&#xff0c;需要實現溫度的表盤展示效果 實現思路&#xff1a; 通過提示聲QLabel控價類&#xff0c;實現報盤的旋轉和展示效果 1. 編寫一個QLabel的類MyQLabel,實現兩個方法 1. void paintEvent(QPaintEvent *event); //重繪函數 2. void valueChanged(int va…

通信系統中物理層與網絡層聯系與區別

在通信系統中&#xff0c;物理層和網絡層是OSI&#xff08;開放系統互連&#xff09;模型中的兩個重要層次&#xff0c;分別位于協議棧的最底層和第三層。它們在功能、職責和實現方式上有顯著的區別&#xff0c;但同時也在某些方面存在聯系。以下是物理層與網絡層的聯系與區別的…

【深度學習】Pytorch的深入理解和研究

一、Pytorch核心理解 PyTorch 是一個靈活且強大的深度學習框架&#xff0c;廣泛應用于研究和工業領域。要深入理解和研究 PyTorch&#xff0c;需要從其核心概念、底層機制以及高級功能入手。以下是對 PyTorch 的深入理解與研究的詳細說明。 1. 概念 動態計算圖&#xff08;D…

23種設計模式 - 解釋器模式

模式定義 解釋器模式&#xff08;Interpreter Pattern&#xff09;是一種行為型設計模式&#xff0c;用于為特定語言&#xff08;如數控系統的G代碼&#xff09;定義文法規則&#xff0c;并構建解釋器來解析和執行該語言的語句。它通過將語法規則分解為多個類&#xff0c;實現…