單調(diào)隊列&單調(diào)棧

就是一些很神奇的數(shù)據(jù)結(jié)構(gòu)

A:最大矩形

題目:

給一個直方圖,求直方圖中的最大矩形的面積愿阐。例如亭引,下面這個圖片中直方圖的高度從左到右分別是2, 1, 4, 5, 1, 3, 3, 他們的寬都是1,其中最大的矩形是陰影部分虾啦。

input:

輸入包含多組數(shù)據(jù)翠霍。每組數(shù)據(jù)用一個整數(shù)n來表示直方圖中小矩形的個數(shù)锭吨,你可以假定1 <= n <= 100000. 然后接下來n個整數(shù)h1, …, hn, 滿足 0 <= hi <= 1000000000. 這些數(shù)字表示直方圖中從左到右每個小矩形的高度,每個小矩形的寬度為1寒匙。 測試數(shù)據(jù)以0結(jié)尾零如。

output:

對于每組測試數(shù)據(jù)輸出一行一個整數(shù)表示答案。

在矩形條里面選取最大的矩形,首先想到暴力做法的話埠况,估計必須會有O(n^2)的復(fù)雜度(每個點都找左右延申最遠) 這樣耗費不可接受耸携。所以就要用到這里的數(shù)據(jù)結(jié)構(gòu),單調(diào)棧
所謂單調(diào)棧就是辕翰,以遞增棧為例夺衍,如果加入元素小于棧頂,入棧喜命,否則棧頂出棧沟沙,直到滿足元素小于棧頂或者棧空壁榕。

對于矩形柱矛紫,從當前向右,要使得必須大于當前的矩形柱才可以延申牌里。因此維護的是一個遞增棧颊咬,是當前元素i被pop 的時候就說明這時候要加入的這個元素比當前元素小,也就是能夠向右拓展的最大距離了牡辽。
向左拓展的距離類似喳篇,反向建立一個單增棧即可。
(說起來簡單其實需要自己稍微模擬一下)

#include<iostream>
#include<stack>
using namespace std;
const int N = 100000 + 50;
long long maxit(long long a, long long b)
{
    if (a > b)
    {
        return a;
    }
    else
    {
        return b;
    }
}
int lf, rt;
int hight;
long long ans;
long long n, a[N], L[N], R[N], st[N];
int main()
{
    cin >> n;
    while(n!=0)
    {
        
    ans=0;
    stack<long long> A;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int i = 0;
    while (i < n)
    {
        if (A.empty() || a[A.top()] <= a[i])
        {
            A.push(i);
            i++;
        }
        else
        {
            int tp = A.top();
            A.pop();
            long long area;
            if (A.empty())
            {
                area = a[tp] * i;
                ans = maxit(ans, area);
            }
            else
            {
                area = a[tp] * (i -1- A.top());
                ans = maxit(ans, area);
            }
        }
    }
    while (!A.empty())
    {
        long long area;
        int tp = A.top();
        A.pop();
        if (A.empty())
        {
            area = a[tp] * i;
            ans = maxit(ans, area);
        }
        else
        {
            area = a[tp] * (i -1-A.top());
            ans = maxit(ans, area);
        }
    }
    cout << ans << endl;
    cin>>n;
    //for(int i=0)
    }
    return  0;
}

直接用了stl态辛,據(jù)說手動模擬更簡單麸澜?

B:TT’s Magic Cat

題目:

給定一個數(shù)組,在其(l,r)區(qū)間內(nèi)的每個值都增加k奏黑,求q輪后的數(shù)組炊邦。

input:

第一行包含兩個整數(shù)n,q(1≤n熟史,q≤2?105)分別表示數(shù)組的長度和操作的輪數(shù)
第二行包含序列a的元素:整數(shù)a1馁害、a2、…以故、an(-106≤ai≤106)蜗细。
接下來是q行,每一行代表一個操作怒详。第i行包含用于第i操作的三個整數(shù)l、r和c(1≤l≤r≤n踪区,-105≤c≤105)昆烁。

output:

打印出變化后的數(shù)組

暴力:O(n^2)的時間復(fù)雜度無法接受。
所以要做的就是用新的辦法缎岗。我們用的是差分法》 那么啥是差分


image.png

(這樣/我知道手寫不是一個好習(xí)慣orz

#include<iostream>
using namespace std;
long long a[300020];
long long b[300020];
int main()
{
    int m,n;
    cin>>n>>m;
    int lf,rt;
    for(int i=0;i<n;i++)   
    {
        scanf("%lld",&a[i]);
    }
    b[0]=a[0];
    for(int i=1;i<n;i++)   
    {
        b[i]=a[i]-a[i-1];
    }
    for(int i=0;i<m;i++)   
    {
        int value;
        scanf("%d%d%d",&lf,&rt,&value);
        b[lf-1]=b[lf-1]+value;
        b[rt]=b[rt]-value;
    }
    a[0]=b[0];
    for(int i=1;i<n;i++)   
    {
        a[i]=b[i]+a[i-1];
    }
    for(int i=0;i<n;i++)   
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;
    return 0;
}

C:平衡字符串

題目:

一個長度為 n 的字符串 s静尼,其中僅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四種字符。

如果四種字符在字符串中出現(xiàn)次數(shù)均為 n/4,則其為一個平衡字符串鼠渺。

現(xiàn)可以將 s 中連續(xù)的一段子串替換成相同長度的只包含那四個字符的任意字符串鸭巴,使其變?yōu)橐粋€平衡字符串,問替換子串的最小長度?

如果 s 已經(jīng)平衡則輸出0拦盹。

input:

一行字符表示給定的字符串s

output:

一個整數(shù)表示答案

樣例輸入:

QWER

樣例輸出:

0

樣例輸入:

QQWE

樣例輸出:

1

樣例輸入:

QQQE

樣例輸出:

2

樣例輸入:

QQQQ

樣例輸出:

3
這題要介紹的辦法是鹃祖,尺取法。簡單說就是拿著一個游標尺子去取長度普舆。
不符合條件恬口,右標右移,符合條件沼侣,左標右移祖能。當然尺取的區(qū)間需要連續(xù)。
顯然這道題符合這樣的條件蛾洛。养铸。那么剩下的就是進行統(tǒng)計了,統(tǒng)計區(qū)間外面的字母數(shù)量(首先每個字母該有幾個我們是知道的) 然后……區(qū)間內(nèi)部的字母都可以作為自由的去填補這些缺口轧膘,看看缺口能不能被補上確定是不是“符合條件”

#include<iostream>
#include<string>
#include<cstring>
#include<string.h>
using namespace std;
int a[4];
int ziyouji=0;
int bl(char c)
{
    if(c=='Q') return 0;
    else if(c=='W') return 1;
    else if(c=='E') return 2;
    else if(c=='R') return 3;
}
int minit(int a,int b)
{
    if(a<b) return a;
    else return b;
}
bool queren(int ll)
{
    int tx=0;
    for(int i=0;i<4;i++)
    {
        if(a[i]>ll)
        {
            return false;
        }
        tx+=ll-a[i];
    }
    if(tx==ziyouji)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
int main()
{
    int now;
    
    memset(a,0,sizeof(a));
    string x;
    cin>>x;
    int ans=x.length();
    int t=x.length();
    for(int i=0;i<t;i++)
    {
        if(x[i]=='Q') a[0]++;
        else if(x[i]=='W') a[1]++;
        else if(x[i]=='E') a[2]++;
        else if(x[i]=='R') a[3]++;
    }
    int tl=t/4;
    int l=0,r=0;
    while(r<x.length())
    {
        if(queren(tl))
        {
            //cout<<"hello"<<l<<" "<<r<<endl;
            ans=minit(ans,r-l);
            a[bl(x[l])]++;
            l++;
            ziyouji--;
        }
        else
        {
            //cout<<"hi"<<l<<" "<<r<<endl;
            a[bl(x[r])]--;
            ziyouji++;
            r++;
        }
    }

    cout<<ans<<endl;
    return 0;
}

D:滑動窗口
題目:
ZJM 有一個長度為 n 的數(shù)列和一個大小為 k 的窗口, 窗口可以在數(shù)列上來回移動. 現(xiàn)在 ZJM 想知道在窗口從左往右滑的時候钞螟,每次窗口內(nèi)數(shù)的最大值和最小值分別是多少. 例如:
數(shù)列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3.


image.png

input:
輸入有兩行。第一行兩個整數(shù)n和k分別表示數(shù)列的長度和滑動窗口的大小扶供,1<=k<=n<=1000000筛圆。第二行有n個整數(shù)表示ZJM的數(shù)列。

output:
輸出有兩行椿浓。第一行輸出滑動窗口在從左到右的每個位置時太援,滑動窗口中的最小值。第二行是最大值扳碍。

樣例輸入:
8 3
1 3 -1 -3 5 3 6 7
樣例輸出:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
涉及到和第一題類似的數(shù)據(jù)結(jié)構(gòu)提岔,單調(diào)隊列。但和單調(diào)棧不同的是單調(diào)隊列是雙向的笋敞。
找局部的最大值和最小值碱蒙,
1.首先維護雙端隊列的單調(diào)性,(假設(shè)從隊頭到隊尾遞減)當前元素若比隊尾元素值小夯巷,則彈出元素直到滿足條件赛惩。
2.同時要維護窗口內(nèi)的元素個數(shù),如果隊首的元素已經(jīng)在窗口外趁餐,就把他彈出喷兼。
3.每一次循環(huán)的隊首元素就是當前窗口的最大值或者是最小值。
(同樣不太好理解QAQ)

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<deque>
#define MAXN 1000010
int a[MAXN];
int maxx[MAXN],minn[MAXN];
using namespace std;
int n,k;    
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    deque<int> q;//儲存下標
    for(int i=1;i<=k-1;i++)
    {   while(!q.empty()&&a[q.back()]>a[i])
            q.pop_back();
        q.push_back(i);
    }
    for(int i=k;i<=n;i++)//窗口從k開始向右移動 維護一個單增隊列
    {
        while(!q.empty()&&a[q.back()]>a[i]) q.pop_back();//先維護單調(diào)性
        q.push_back(i);
        while(!q.empty()&&(i-q.front())>=k) q.pop_front();//然后維護窗口的大小
        minn[i]=q.front();
    }
    q.clear();
    for(int i=1;i<=k-1;i++)
    {   while(!q.empty()&&a[q.back()]<a[i])
            q.pop_back();
        q.push_back(i);
    }
    for(int i=k;i<=n;i++)//窗口從k開始向右移動 維護一個單增隊列
    {
        while(!q.empty()&&a[q.back()]<a[i]) q.pop_back();//先維護單調(diào)性
        q.push_back(i);
        while(!q.empty()&&(i-q.front())>=k) q.pop_front();//然后維護窗口的大小
        maxx[i]=q.front();
    }

    for(int i=k;i<=n;i++)   printf("%d ",a[minn[i]]);
    cout<<endl;
    for(int i=k;i<=n;i++)   printf("%d ",a[maxx[i]]);
    cout<<endl;
    system("pause");
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末后雷,一起剝皮案震驚了整個濱河市季惯,隨后出現(xiàn)的幾起案子吠各,更是在濱河造成了極大的恐慌,老刑警劉巖勉抓,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贾漏,死亡現(xiàn)場離奇詭異,居然都是意外死亡藕筋,警方通過查閱死者的電腦和手機纵散,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來念逞,“玉大人困食,你說我怎么就攤上這事◆岢校” “怎么了硕盹?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叨咖。 經(jīng)常有香客問我瘩例,道長,這世上最難降的妖魔是什么甸各? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任垛贤,我火速辦了婚禮,結(jié)果婚禮上趣倾,老公的妹妹穿的比我還像新娘聘惦。我一直安慰自己,他們只是感情好儒恋,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布善绎。 她就那樣靜靜地躺著,像睡著了一般诫尽。 火紅的嫁衣襯著肌膚如雪禀酱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天牧嫉,我揣著相機與錄音剂跟,去河邊找鬼。 笑死酣藻,一個胖子當著我的面吹牛曹洽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辽剧,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼衣洁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抖仅?” 一聲冷哼從身側(cè)響起坊夫,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撤卢,沒想到半個月后环凿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡放吩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年智听,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渡紫。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡到推,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惕澎,到底是詐尸還是另有隱情莉测,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布唧喉,位于F島的核電站捣卤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏八孝。R本人自食惡果不足惜董朝,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望干跛。 院中可真熱鬧子姜,春花似錦、人聲如沸楼入。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浅辙。三九已至扭弧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間记舆,已是汗流浹背鸽捻。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泽腮,地道東北人御蒲。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像诊赊,于是被迫代替她去往敵國和親厚满。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,370評論 0 5
  • 說明: 本文中出現(xiàn)的所有算法題皆來自疟贪酰客網(wǎng)-劍指Offer在線編程題碘箍,在此只是作為轉(zhuǎn)載和記錄遵馆,用于本人學(xué)習(xí)使用,不...
    秋意思寒閱讀 1,148評論 1 1
  • 本文出自 Eddy Wiki 丰榴,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-code.h...
    eddy_wiki閱讀 9,334評論 0 30
  • 1.二維數(shù)組的查找 題目描述:在一個二維數(shù)組中(每個一維數(shù)組的長度相同)货邓,每一行都按照從左到右遞增的順序排序,每一...
    少年夢游計_3403閱讀 1,158評論 0 1
  • “你怎么又把藥吃差了四濒?不是跟你說了幾遍嗎换况?這種藥一天吃一次。我離開的時候已經(jīng)給你吃了盗蟆,你怎么又吃了一次呀戈二?”女兒站...
    夢在雨巷閱讀 415評論 2 3