【算法】單調隊列單調棧

一、單調隊列

? ?用來維護一段區間內的最大值或最小值,例如滑動窗口區間最值等問題。

基本概念

單調隊列是一種存儲數據的隊列,其中元素的順序是單調遞增或單調遞減的。在算法競賽中,我們一般使用兩個單調隊列,一個維護單調遞增序列,另一個維護單調遞減序列。單調隊列是一個雙端隊列

代碼如下:

#include <iostream>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;void output(vector<int>& arr) {int n = arr.size(), len = 0;for (int i = 0; i < n; i++) len += printf("%3d", i);cout << "\n";for (int i = 0; i < len; i++)printf("-");cout << "\n";for (int i = 0; i < n; i++) len += printf("%3d", arr[i]);cout << "\n";
}int main(){int n, k;cin >> n >> k;vector<int> arr;deque<int> q;for (int i = 0, a; i < n; i++) {cin >> a;arr.push_back(a);}output(arr);for (int i = 0; i < n; i++) {while (!q.empty() && arr[q.back()] > arr[i])q.pop_back();q.push_back(i); //壓入下標if (i - q.front() == k) q.pop_front(); //彈出隊頭printf("[%d, %d] = arr[%d] = %d \n",max(i - k + 1, 0), i,q.front(),arr[q.front()]);}
}

滑動窗口

154. 滑動窗口 - AcWing題庫

滑動窗口是一類問題,需要在一個長度為n的序列中,找到所有長度為k的連續子序列中的最大值或最小值。使用單調隊列可以在O(n)的時間復雜度內解決該問題。

具體做法如下:

(1)將前k個元素插入單調隊列中,并記錄隊列的最大值或最小值。
(2)從第k+1個元素開始,每次將一個新的元素插入單調隊列中。
(3)插入時,先將隊列中所有小于等于該元素的隊尾元素出隊,保證隊列中的元素單調遞減。
(4)將該元素插入隊尾,并記錄隊列的最大值或最小值。
(5)將長度為k的子序列的最大值或最小值輸出即可。

方法1:(數組實現)

#include <iostream>
using namespace std;const int N = 1e6 + 10;
int q[N], a[N]; //數組q用來存下標
int main() {int n, k;cin >> n >> k;for (int i = 0; i < n; i++) cin >> a[i];//找滑動窗口最小值int hh = 0, tt = -1;for (int i = 0; i < n; i++) {if (i - q[hh] == k) hh++; //隊頭彈出元素while (hh <= tt && a[q[tt]] > a[i]) tt--; //隊尾彈出元素q[++tt] = i; //壓入下標if (i - k + 1 >= 0)printf("%d ", a[q[hh]]);}printf("\n");//找滑動窗口最大值hh = 0, tt = -1;for (int i = 0; i < n; i++) {if (i - q[hh] == k) hh++; //隊頭彈出元素while (hh <= tt && a[q[tt]] < a[i]) tt--; //隊尾彈出元素q[++tt] = i; //壓入下標if (i - k + 1 >= 0)printf("%d ", a[q[hh]]);}return 0;
}

方法2:(雙端隊列)

#include <iostream>
#include <deque>
#include <vector>
using namespace std;int main() {int n, k;cin >> n >> k;vector<int> arr(n);deque<int> q;for (int i = 0; i < n; i++)cin >> arr[i];for (int i = 0; i < n; i++) {if (i - q.front() == k) q.pop_front();while (!q.empty() && arr[q.back()] > arr[i])q.pop_back();q.push_back(i);if (i - k + 1 >= 0) cout << arr[q.front()] << " ";}cout << endl;q.clear();for (int i = 0; i < n; i++) {if (i - q.front() == k) q.pop_front();while (!q.empty() && arr[q.back()] < arr[i])q.pop_back();q.push_back(i);if (i - k + 1 >=0) cout << arr[q.front()] << " ";}return 0;
}

區間最值

135. 最大子序和 - AcWing題庫

需要在一個長度為n的序列中,找到所有長度為k的子序列中的最大值或最小值。使用單調隊列可以在O(n)的時間復雜度內解決該問題。

其實現方法與上面類似,但是需要注意:

  • 區間最值問題是在不限制子序列連續性的情況下,找到子序列中的最大值或最小值。
  • 而滑動窗口問題則是在限制子序列必須連續的情況下,找到所有長度為k的子序列中的最大值或最小值。

方法1:(數組實現)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;typedef long long LL;const int N = 1e6 + 10;
int q[N];
LL s[N];
int main()
{int n, m;cin >> n >> m;//處理為前綴和序列for (int i = 1; i <= n; i++) {cin >> s[i];s[i] += s[i - 1];}LL res = -1e10;int hh = 0, tt = 0;for (int i = 1; i <= n; i++) {if (i - q[hh] > m) hh++;res = max(res, s[i] - s[q[hh]]);while (hh <= tt && s[q[tt]] >= s[i]) tt--;q[++tt] = i;}cout << res << "\n";return 0;
}

方法2:(雙端隊列)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;int main()
{int n, m;cin >> n >> m;//處理前綴和vector<LL> s(n + 1);s.push_back(0);deque<LL> q;for (int i = 1; i <= n; i++) {cin >> s[i];s[i] += s[i - 1];}q.push_back(0);LL res = -1e6;for (int i = 1; i <= n; i++) {if (i - q.front() > m) q.pop_front();res = max(res, s[i] - s[q.front()]);while (!q.empty() && s[q.back()] >= s[i]) q.pop_back();q.push_back(i);}cout << res << "\n";return 0;
}


二、單調棧

基本概念

單調棧實際上就是棧,只是利用了一些巧妙的邏輯,使得每次新元素入棧后,棧內的元素都保持有序(單調遞增或單調遞減),即從隊首不彈出元素的單調隊列就是單調棧。

作用:用于找最近小于關系(單調遞增)和最近大于關系(單調遞減)

代碼如下:

#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;void output(vector<int>& arr) {int n = arr.size(), len = 0;for (int i = 0; i < n; i++) len += printf("%3d", i);cout << "\n";for (int i = 0; i < len; i++)printf("-");cout << "\n";for (int i = 0; i < n; i++) len += printf("%3d", arr[i]);cout << "\n";
}int main(){int n;cin >> n;vector<int> arr;arr.push_back(-1); //假如極小值為-1stack<int> s;for (int i = 0, a; i < n; i++) {cin >> a;arr.push_back(a);}arr.push_back(-1); //假如極小值為-1vector<int> l(arr.size() + 1), r(arr.size() + 1);output(arr);//右側for (int i = 0;  i < arr.size(); i++) {while (!s.empty() && arr[s.top()] > arr[i]) {r[s.top()] = i;s.pop();}s.push(i);}//左側 (倒著掃描)while (!s.empty()) s.pop();for (int i = arr.size() - 1; i >= 0; i--) {while (!s.empty() && arr[s.top()] > arr[i]) {l[s.top()] = i;s.pop();}s.push(i);}for (int i = 1; i <= n; i++) {printf("arr[%d] = %d, right : arr[%d] = %d, left : arr[%d] = %d\n",i, arr[i],r[i], arr[r[i]],l[i], arr[l[i]]);}return 0;
}

數組實現單調棧:

830. 單調棧

#include <iostream>
using namespace std;
const int N = 10010;int stk[N], tt ;
int main()
{int n;cin >> n;while(n--){int x;cin>>x;while(tt&&stk[tt]>=x) tt--;if(tt==0) printf("-1 ");else printf("%d ",stk[tt]);stk[++tt]=x;}return 0;
}

三、總結

單調隊列:擅長維護區間【最大/最小】值,最小值對應單調遞增隊列

單調棧:擅長維護最近【大于/小于】關系,

從左側先入棧就是維護左側最近關系

從右側先入棧,就是維護右側最近關系。

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

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

相關文章

【版面費優惠丨ACM獨立出版丨接受全文摘要投稿】2024年生物醫藥和智能技術國際學術會議(ICBIT 2024,8月23-25)

“2024年生物醫藥和智能技術國際學術會議&#xff08;ICBIT 2024&#xff09;”擬定于2024年8月23-25日于珠海召開。近年來&#xff0c;智能技術已經逐漸走入生物醫藥領域&#xff0c;并在與生物醫藥領域的融合創新中凸顯出巨大的發展潛力和社會價值。人工智能技術在生物醫藥領…

水處理基本知識

RO反滲透程序設計軟件下載 水處理基本知識 純水制備的核心工藝 核心工藝&#xff1a;純水&#xff08;超純水&#xff09;制備的主要處理工藝&#xff0c;結合前處理&#xff08;預處理&#xff09;工藝&#xff0c;輔助工藝及特殊工藝&#xff0c;組成完整的純水制備工藝。結…

優質作品集秘訣:8個技巧讓你的作品脫穎而出

制作一個高質量的投資組合不僅可以展示你的技能和創造力&#xff0c;還可以幫助你在求職和職業發展中脫穎而出。如何制作高質量的投資組合&#xff1f;今天給大家講述作品集的 8 個實用技能&#xff0c;幫助你制作出令人印象深刻的作品集&#xff01; 1、精選作品 并不是所有…

飛睿智能會議室靜止雷達人體檢測傳感器,實時監測使用狀態,有人、無人智能感應節能減

在這個科技日新月異的時代&#xff0c;每一個細微的創新都可能成為推動行業創新的關鍵力量。今天&#xff0c;讓我們聚焦于一項看似不起眼卻實則潛力無限的技術——飛睿智能靜止雷達人體檢測傳感器&#xff0c;以及它在會議室這一商務交流核心區域中的巧妙應用。想象一下&#…

前端Canvas入門——怎么用Canvas畫一些簡單的圖案

Canvas作為前端的畫圖工具&#xff0c;其實用途還是蠻廣泛的&#xff0c;但是很多前端學習課程其實都很少涉及到這塊內容。 于是乎&#xff0c;就寫下這個了。 當然啦&#xff0c;目前還在學習摸索中。 一些實戰代碼&#xff0c;僅供參考&#xff1a; <canvasid"ctx&…

EtherCAT總線冗余讓制造更安全更可靠更智能

冗余定義 什么是總線冗余功能&#xff1f;我們都知道&#xff0c;EtherCAT現場總線具有靈活的拓撲結構&#xff0c;設備間支持線型、星型、樹型的連接方式&#xff0c;其中線型結構簡單、傳輸效率高&#xff0c;大多數的現場應用中也是使用這種連接方式&#xff0c;如下圖所示…

【Qt課設】基于Qt實現的中國象棋

一、摘 要 本報告討論了中國象棋程序設計的關鍵技術和方法。首先介紹了中國象棋的棋盤制作&#xff0c;利用Qt中的一些繪畫類的函數來進行繪制。在創作中國象棋棋子方面&#xff0c;首先&#xff0c;我們先定義一下棋子類&#xff0c;將棋子中相同的部分進行打包&#xff0c;使…

idea推送到gitee 401錯誤

在idea上推送時遇到這樣的問題&#xff0c;解決方法如下&#xff1a; 在https://的后面加上 用戶名:密碼 然后再提交就ok啦&#xff01;

三、SpringMVC

三、SpringMVC 1、SpringMVC簡介 1.1、什么是MVC MVC是一種軟件架構的思想&#xff0c;將軟件按照模型、視圖、控制器來劃分 M&#xff1a;Model&#xff0c;模型層&#xff0c;指工程中的JavaBean&#xff0c;作用是處理數據 JavaBean分為兩類&#xff1a; 一類稱為實體…

c語言實戰-極簡掃雷

C語言/c寫的C語言實戰項目掃雷 結構比較清晰&#xff0c;僅供參考&#xff1a; 核心是掃雷的遞歸算法實現 上代碼: #include <stdio.h> #include <stdlib.h> #include <time.h>#define SIZE 10 #define MINES 15char board[SIZE][SIZE]; // 游戲棋盤// 初…

Oracle的主要特點是什么?應用場景有哪些?

主要特點&#xff1a; 高可靠性&#xff1a;Oracle數據庫具有高度的可靠性&#xff0c;能夠確保數據的安全和穩定性。 高性能&#xff1a;提供高性能的數據處理和查詢能力&#xff0c;可以處理大規模的數據量。 良好的擴展性&#xff1a;支持水平和垂直的擴展&#xff0c;可以輕…

CloudWatch Logs Insights 詳解

CloudWatch Logs Insights 是 AWS 提供的強大日志分析工具,允許您快速、交互式地搜索和分析日志數據。本文將詳細介紹使用 CloudWatch Logs Insights 所需的權限、常用查詢方法,以及一些實用的查詢示例。 1. 所需權限 要使用 CloudWatch Logs Insights,用戶需要具備以下 I…

代碼隨想錄-Day55

42. 接雨水 給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖&#xff0c;計算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 輸入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 輸出&#xff1a;6 解釋&#xff1a;上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高…

CentOS7二進制安裝和YUM安裝mongodb,服務器無法安裝5.0以上的 mongodb 數據庫報錯 Illegal instruction

文章目錄 MongoDB 安裝二進制安裝YUM 安裝 Tips:1、MongoDB安裝問題2、MongoDB登錄3、MongoDB排序時內存大小限制和創建索引4、創建用戶5、Java yaml使用密碼連接mongodb6、MongoDB增刪改查 MongoDB 安裝 二進制安裝 [rootmysql5-7 mongodb-6.0.4]# cat start.sh #!/bin/bash…

js使用proxy代理監聽控制事件

本文為proxy代理的實例應用&#xff0c;有關代理的內容可以參考&#xff1a; js語法---理解反射Reflect對象和代理Proxy對象 監聽事件 要監聽dom元素的事件&#xff0c;我們會采用回調觸發的方式來執行操作&#xff0c; 而觸發事件的過程很明顯是一個異步操作&#xff0c;異…

Docker 使用基礎(1)—鏡像倉庫

&#x1f3ac;慕斯主頁&#xff1a;修仙—別有洞天 ??今日夜電波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━?&#x1f49f;──────── 4:20 &#x1f504; ?? ? …

Pinia在vue項目中的使用

Pinia是Vue 3官方推薦的狀態管理模式&#xff0c;由尤雨溪創建并集成到了 Vue.js 中&#xff0c;它是一個輕量級、純粹基于函數的思想實現的應用狀態管理庫。Pinia的設計理念類似于Redux&#xff0c;但它更簡單易用&#xff0c;更適合于小型到中型的單文件組件應用。 在Vue 3項…

android13 固定U盤鏈接 SD卡鏈接 TF卡鏈接 硬盤鏈接

1.前言 有些客戶使用的應用并不帶有自動監聽U盤 sd卡廣播的代碼,使用的代碼是固定的地址,這樣的話,就需要我們將系統的掛載目錄固定了。 原始路徑 /storage/3123-19FA 增加鏈接 /storage/upan_000 -> /storage/3123-19FA 2. 首先如果是應用本身監聽的話,使用的是 /…

【Linux線程篇】探索Linux多線程:并行編程的入門指南

W...Y的主頁 &#x1f60a; 代碼倉庫分享&#x1f495; Linux線程概念 什么是線程 在一個程序里的一個執行路線就叫做線程&#xff08;thread&#xff09;。更準確的定義是&#xff1a;線程是“一個進程內部的控制序列”一切進程至少都有一個執行線程線程在進程內部運行&am…

【國產開源可視化引擎Meta2d.js】數據

數據 Meta2d.js是由數據驅動顯示的。圖紙和圖元支持任意數據。 內置屬性 基于“約定優于配置”原則&#xff0c;Meta2d.js引擎會有一些內置屬性名&#xff0c;例如id表示唯一標識、name表示圖元名稱、text表示文本、color表示顏色等。 內置屬性有固定含義&#xff0c;影響顯…