數(shù)據(jù)結(jié)構(gòu) | 棧都知道,單調(diào)棧有了解嗎缠诅?

點(diǎn)贊關(guān)注溶浴,不再迷路,你的支持對(duì)我意義重大管引!

?? Hi士败,我是丑丑。本文「數(shù)據(jù)結(jié)構(gòu) & 算法」| 導(dǎo)讀 —— 登高博見(jiàn) 已收錄褥伴,這里有 Android 進(jìn)階成長(zhǎng)路線筆記 & 博客谅将,歡迎跟著彭丑丑一起成長(zhǎng)。(聯(lián)系方式在 GitHub)

歷史上的今天

1938 年 3 月重慢,香農(nóng)發(fā)表時(shí)代論文饥臂。
這就是《繼電器和開(kāi)關(guān)電路的符號(hào)分析》("A Symbolic Analysis of Relay and Switching Circuits")。香農(nóng)在這篇論文中展示了如何把布爾代數(shù)的各種運(yùn)算應(yīng)用在開(kāi)關(guān)電路中似踱,將布爾代數(shù)中的 “真” “假” 和電路系統(tǒng)中的 “開(kāi)” “關(guān)” 對(duì)應(yīng)起來(lái)隅熙,并用 1 和 0 來(lái)標(biāo)示稽煤。這篇論文是開(kāi)關(guān)與邏輯電路理論和設(shè)計(jì)的開(kāi)山之作,也是所有數(shù)字計(jì)算機(jī)運(yùn)行的基礎(chǔ)猛们。 —— 《了不起的程序員》


前言

  • 單調(diào)棧是一種非常適合處理 下一個(gè)更大元素(Next Greater Number ) 問(wèn)題的數(shù)據(jù)結(jié)構(gòu)念脯,在面試中比較冷門,建議應(yīng)試者合理安排學(xué)習(xí)時(shí)間弯淘;
  • 在這篇文章里绿店,我將梳理單調(diào)棧的基本知識(shí) & 常考題型庐橙。如果能幫上忙假勿,請(qǐng)務(wù)必點(diǎn)贊加關(guān)注,這真的對(duì)我非常重要态鳖。

目錄


1. 單調(diào)椬啵基礎(chǔ)

1.1 定義

棧(Stack)是一種滿足后進(jìn)先出(LIFO)邏輯的數(shù)據(jù)結(jié)構(gòu),大家都很熟悉了浆竭,單調(diào)棧實(shí)際上就是在棧的基礎(chǔ)上增加單調(diào)的性質(zhì)浸须。

比如有序就是最耳熟能詳?shù)膯握{(diào)性,每次新元素入棧時(shí)邦泄,我們可以采用一些額外的邏輯保證棧內(nèi)元素都是有序的删窒,這樣我們就得到了一個(gè)單調(diào)棧。出棧的時(shí)候不需要增加額外的邏輯顺囊,因?yàn)閷?duì)于一個(gè)單調(diào)棧(或者下篇文章提到的單調(diào)隊(duì)列)肌索,移除首尾的元素后剩下的元素肯定還是滿足單調(diào)性的。

單調(diào)性

單調(diào)性(monotonicity)也可以叫做增減性特碳,可以定性地描述兩個(gè)變量之間的關(guān)系诚亚。當(dāng)變量x在其定義區(qū)間內(nèi)增大時(shí),函數(shù)y= f(x)隨著增大(或減形缗摇)站宗,則稱函數(shù) y 在該區(qū)間單調(diào)遞增(或單調(diào)遞減)。

1.2 作用

理解了單調(diào)棧的定義硅瞧,下一個(gè)問(wèn)題就是單調(diào)棧有什么用份乒?

老讀者應(yīng)該有印象,我們不是第一次討論單調(diào)性了腕唧。我們?cè)?《算法 | 下次面試遇到二分查找或辖,別再寫錯(cuò)了》 就已經(jīng)提過(guò)單調(diào)性。還記得嗎枣接,我們說(shuō)單調(diào)性是二分查找的必要條件颂暇。

為什么單調(diào)性是二分查找必要條件呢?因?yàn)樵诙植檎依锏蹋覀冃枰獙?duì)比目標(biāo)數(shù)與數(shù)組的中位數(shù)耳鸯,來(lái)確定目標(biāo)數(shù)是落在左半?yún)^(qū)間湿蛔,還是右半?yún)^(qū)間。舉個(gè)例子县爬,對(duì)于一個(gè)單調(diào)遞增序列阳啥,當(dāng)中位數(shù)小于目標(biāo)數(shù)時(shí),那我們可以確定:左半?yún)^(qū)間一定不是解财喳,右半?yún)^(qū)間可能有解察迟。

此時(shí),問(wèn)題規(guī)模減少了一半(減治)耳高,整個(gè)二分查找算法的時(shí)間復(fù)雜度從暴力查找 O(n)扎瓶,降低到O(lgn),這里面單調(diào)性功不可沒(méi)泌枪。

回到主題概荷,單調(diào)棧里的單調(diào)性有什么用?棧里雖然沒(méi)有中位數(shù)的概念碌燕,但是有棧頂?shù)母拍钗笾ぁN覀兛梢岳脳m攣?lái)判斷棧內(nèi)其他元素是否存在解。 舉個(gè)例子修壕,對(duì)于一個(gè)從棧底到棧頂單調(diào)遞增的棧雷厂,當(dāng)棧頂元素小于目標(biāo)數(shù),那么我們可以確定:棧內(nèi)元素都是小于目標(biāo)數(shù)的叠殷;而當(dāng)棧頂元素大于目標(biāo)數(shù),那么只有棧頂前面一部分元素大于目標(biāo)數(shù)诈皿。

小結(jié):利用了單調(diào)的特性林束,以空間換時(shí)間優(yōu)化時(shí)間復(fù)雜度。

1.3 局限性

相比于其他數(shù)據(jù)結(jié)構(gòu)稽亏,單調(diào)棧并不能覆蓋太大的問(wèn)題域壶冒,所以這種數(shù)據(jù)結(jié)構(gòu)的應(yīng)用價(jià)值就打折扣了。也只有 下一個(gè)更大元素(Next Greater Number ) 這一類問(wèn)題截歉,精準(zhǔn)命中單調(diào)棧的射程范圍胖腾。在 第 3 節(jié) 中,我整理了大量典型例題瘪松,應(yīng)該能覆蓋常見(jiàn)的題型咸作,多去看看加深理解。


2. 單調(diào)棧解題框架

前面的內(nèi)容相信大家很快就能理解了宵睦,我們直接看單調(diào)棧的原始題目 739. 每日溫度(Medium)记罚,并根據(jù)這個(gè)例子來(lái)討論單調(diào)棧的解題框架。

請(qǐng)根據(jù)每日氣溫列表壳嚎,重新生成一個(gè)列表桐智。對(duì)應(yīng)位置的輸出為:要想觀測(cè)到更高的氣溫末早,至少需要等待的天數(shù)。如果氣溫在這之后都不會(huì)升高说庭,請(qǐng)?jiān)谠撐恢糜?0 來(lái)代替然磷。

例如,給定一個(gè)列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]刊驴,你的輸出應(yīng)該是 [1, 1, 4, 2, 1, 1, 0, 0]姿搜。

提示:氣溫 列表長(zhǎng)度的范圍是 [1, 30000]。每個(gè)氣溫的值的均為華氏度缺脉,都是在 [30, 100] 范圍內(nèi)的整數(shù)痪欲。

這個(gè)問(wèn)題的暴力解法很容易想到:對(duì)每個(gè)元素掃描后續(xù)的每個(gè)元素,找到第一個(gè)更大的元素攻礼,整體時(shí)間復(fù)雜度是O(n^2)业踢,空間復(fù)雜度是O(1)

下面我們來(lái)討論單調(diào)棧的解法:

  • 1礁扮、從左到右遍歷每個(gè)元素知举,維護(hù)一個(gè)單調(diào)遞增棧,棧中存儲(chǔ)的是 「未確定解的元素下標(biāo)」太伊,下標(biāo)對(duì)應(yīng)的每日溫度遞增雇锡;
  • 2、當(dāng)棧為空僚焦,將當(dāng)前元素下標(biāo)入棧锰提;
  • 3.1 當(dāng)棧不為空,如果當(dāng)前元素大于等于棧頂元素芳悲,那么循環(huán)彈出棧頂元素立肘,直到棧為空或者當(dāng)前元素小于棧頂元素;
  • 3.2 當(dāng)棧不為空名扛,如果當(dāng)前元素小于棧頂元素谅年,說(shuō)明當(dāng)前元素小于棧內(nèi)所有元素(單調(diào)性),將當(dāng)前元素入棧肮韧;
  • 4融蹂、元素出棧時(shí),計(jì)算下標(biāo)的差值就是間隔天數(shù)弄企。

—— 圖片引用自 LeetCode

這個(gè)問(wèn)題的題解基本上就是單調(diào)棧的解題框架:

fun dailyTemperatures(T: IntArray): IntArray {
    val result = IntArray(T.size) { 0 }

    1超燃、維護(hù)單調(diào)遞增棧
    val stack = ArrayDeque<Int>()

    for (index in T.indices) {
        while (!stack.isEmpty() && T[stack.peek()] < T[index]) {
            2、彈出棧頂小于等于目標(biāo)數(shù)的元素
            val preIndex = stack.pop() // 下標(biāo)出棧
            result[preIndex] = index - preIndex
        }
        3桩蓉、棧頂元素大于目標(biāo)數(shù)淋纲,那么棧內(nèi)所有元素都大于目標(biāo)數(shù)(單調(diào)性)
        stack.push(index) // 下標(biāo)入棧
    }
    return result
}

提示: 你可以看下官方題解的視頻講解加深理解:【官方題解】

復(fù)雜度分析:

  • 時(shí)間復(fù)雜度:O(n)
  • 空間復(fù)雜度:O(n)

雖然代碼中有兩層循環(huán),但是算法的時(shí)間復(fù)雜度并不是O(n^2)院究,這是因?yàn)閮?nèi)層循環(huán)并不是搜索整個(gè)數(shù)組(在暴力解法中洽瞬,內(nèi)層循環(huán)才是搜索整個(gè)數(shù)組)本涕。事實(shí)上,對(duì)于每個(gè)元素伙窃,它最多會(huì)入棧和出棧一次菩颖,不會(huì)因?yàn)閿?shù)據(jù)規(guī)模增大而導(dǎo)致每個(gè)元素增加額外的操作,所以每次操作的時(shí)間復(fù)雜度是O(1)为障。


3. 舉一反三

42. 接雨水(Hard) 【題解】
84. 柱狀圖中最大的矩形(Hard)
402. 移掉K位數(shù)字(Medium)
496. 下一個(gè)更大元素 I(Easy) 【題解】
503. 下一個(gè)更大元素 II(Medium)
739. 每日溫度(Medium) 【題解】
901. 股票價(jià)格跨度(Medium)

4. 總結(jié)

  • 1晦闰、單調(diào)棧是在棧的基礎(chǔ)上,利用了單調(diào)的特性鳍怨,以空間換時(shí)間優(yōu)化時(shí)間復(fù)雜度呻右;
  • 2、當(dāng)遇到下一個(gè)更大元素(Next Greater Number )問(wèn)題時(shí)鞋喇,可以考慮使用單調(diào)棧處理声滥;
  • 3、單調(diào)棧不能覆蓋太大的問(wèn)題域侦香,應(yīng)用價(jià)值不及其他數(shù)據(jù)結(jié)構(gòu)落塑。
  • 4、單調(diào)棧還有一個(gè)孿生兄弟罐韩,你知道是什么嗎憾赁?

參考資料


創(chuàng)作不易散吵,你的「三連」是丑丑最大的動(dòng)力龙考,我們下次見(jiàn)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矾睦,一起剝皮案震驚了整個(gè)濱河市洲愤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顷锰,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡问,死亡現(xiàn)場(chǎng)離奇詭異官紫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)州藕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門束世,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人床玻,你說(shuō)我怎么就攤上這事毁涉。” “怎么了锈死?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵贫堰,是天一觀的道長(zhǎng)穆壕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)其屏,這世上最難降的妖魔是什么喇勋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮偎行,結(jié)果婚禮上川背,老公的妹妹穿的比我還像新娘。我一直安慰自己蛤袒,他們只是感情好熄云,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著妙真,像睡著了一般缴允。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隐孽,一...
    開(kāi)封第一講書(shū)人閱讀 52,785評(píng)論 1 314
  • 那天癌椿,我揣著相機(jī)與錄音,去河邊找鬼菱阵。 笑死踢俄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晴及。 我是一名探鬼主播都办,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼虑稼!你這毒婦竟也來(lái)了琳钉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蛛倦,失蹤者是張志新(化名)和其女友劉穎歌懒,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體溯壶,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡及皂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了且改。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片验烧。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖又跛,靈堂內(nèi)的尸體忽然破棺而出碍拆,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布感混,位于F島的核電站端幼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏浩习。R本人自食惡果不足惜静暂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谱秽。 院中可真熱鬧洽蛀,春花似錦、人聲如沸疟赊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)近哟。三九已至驮审,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吉执,已是汗流浹背疯淫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戳玫,地道東北人熙掺。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像咕宿,于是被迫代替她去往敵國(guó)和親币绩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

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