Leetcode百題斬-棧

終于來到了棧專題,想想之前來阿里的時候就是面試了一道棧最終通過了終面,也是十分懷念了。

739. Daily Temperatures[Medium]

思路:這就是最典型的單調棧問題了。從后向前維護下一個更大值或者下一個更大值的位置。

可以看一下當年面阿里時的博客,一切都還記憶猶新

單調棧專題練--下一個更大元素-CSDN博客

至于棧的數據結構,先嘗試了使用java自身的數據結構Stack,但確實慢的讓人發指,可能其內部各種并行安全機制拖慢了其本身的性能

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperatures(int[] temperatures) {int len = temperatures.length;Deque<Integer> stack = new ArrayDeque<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {stack.pop();}if (!stack.isEmpty()) {result[i] = stack.peek() - i;}stack.push(i);}return result;}
}

多想一下:用鏈表實現棧

再嘗試用鏈表LinkedList來實現棧,速度要快了很多?

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesWithLinkedList(int[] temperatures) {int len = temperatures.length;List<Integer> stack = new LinkedList<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.get(stack.size() - 1)]) {stack.remove(stack.size() - 1);}if (!stack.isEmpty()) {result[i] = stack.get(stack.size() - 1) - i;}stack.add(i);}return result;}
}

多想一下:用雙端隊列來實現棧

Qwen了一下,ai推薦用ArrayDeque,那么來試試,確實比鏈表還要快一些

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesWithDeque(int[] temperatures) {int len = temperatures.length;Deque<Integer> stack = new ArrayDeque<>();int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {stack.pop();}if (!stack.isEmpty()) {result[i] = stack.peek() - i;}stack.push(i);}return result;}
}

多想一下:用原始數組手動實現

一切花里胡哨都不如自己手撕,還是手撕大法好呀

/*
Author Owen_Q
*/
public class DailyTemperature {public static int[] dailyTemperaturesManual(int[] temperatures) {int len = temperatures.length;int[] stack = new int[len];int top = -1;int[] result = new int[len];for (int i = len - 1; i >= 0; i--) {while (top>=0 && temperatures[i] >= temperatures[stack[top]]) {top--;}if (top>=0) {result[i] = stack[top] - i;}stack[++top]=i;}return result;}
}

?

155. Min Stack[Medium]

思路:要求設計一個最小棧,不僅要能進行原有棧操作的基礎上,還要能常數復雜度內求出當前棧的最小值。


/*** Author Owen_Q** a stack that supports push, pop, top, and retrieving the minimum element in constant time.* <p>* Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();**/
public interface MinStack {/*** pushes the element val onto the stack.** @param val the element to be pushed*/void push(int val);/*** removes the element on the top of the stack.*/public void pop();/*** gets the top element of the stack.** @return the top element of the stack*/public int top();/*** retrieves the minimum element in the stack.** @return the minimum element in the stack*/public int getMin();
}

其實考慮動態變更的數據結構實時求最小值,首先想到的就是優先隊列或者堆。但這題需要常數復雜度,那么多思考一下。由于棧的特點是先進后出,即棧底元素一定比上方元素存在的時間長。換句話說,如果某個元素在入棧的那一刻沒有成為最小值,那么其將永遠沒有機會再成為最小值了。因為其下方將永遠存在比其小的元素。那么其實我們只需要一個輔助棧,來記錄一下當前棧內最小元素,和原棧元素同步更新。當入棧元素比棧內最小元素小時,則更新棧內最小元素,否則棧內最小元素維持原值。

/*
Author Owen_Q
*/
public class MinStackDeque implements MinStack {Deque<Integer> stack;Deque<Integer> minStack;public MinStackDeque() {stack = new ArrayDeque<>();minStack = new ArrayDeque<>();}@Overridepublic void push(int val) {stack.push(val);if (minStack.isEmpty() || val <= minStack.peek()) {minStack.push(val);} else {minStack.push(minStack.peek());}}@Overridepublic void pop() {if (stack.isEmpty()) {throw new RuntimeException("stack is empty");}stack.pop();minStack.pop();}@Overridepublic int top() {if (stack.isEmpty()) {throw new RuntimeException("stack is empty");}return stack.peek();}@Overridepublic int getMin() {if (minStack.isEmpty()) {throw new RuntimeException("stack is empty");}return minStack.peek();}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

多想一下:用鏈表模擬棧

想著優化一下,但是由于數組的大小未知,因此不能直接手撕,想到可以嘗試手動模擬鏈表來實現棧。恰巧,不難發現,其實上面使用的兩個棧完全是一模一樣的,因此完全可以把棧最小值當成鏈表節點的一部分,說干就干

/*
Author Owen_Q
*/
public class MinStackNodes implements MinStack {private static class StackNode {int val;int minVal;StackNode next;public StackNode(int val, int minVal, StackNode next) {this.val = val;this.minVal = minVal;this.next = next;}}StackNode stack;public MinStackNodes() {stack = null;}@Overridepublic void push(int val) {if (stack == null) {stack = new StackNode(val, val, null);} else {stack = new StackNode(val, Math.min(val, stack.minVal), stack);}}@Overridepublic void pop() {if (stack == null) {throw new RuntimeException("stack is empty");}stack = stack.next;}@Overridepublic int top() {if (stack == null) {throw new RuntimeException("stack is empty");}return stack.val;}@Overridepublic int getMin() {if (stack == null) {throw new RuntimeException("stack is empty");}return stack.minVal;}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

效果拔群

20. Valid Parentheses[Easy]

思路:括號驗證,括號問題其實很容易想到棧,直接用棧模擬一下即可。最后特判一下如果串長是奇數那么直接返回失敗即可

/*
Author Owen_Q
*/
public class ParenthesesValidator {public static boolean isValid(String s) {int len = s.length();char[] stack = new char[len];int top = 0;if ((len & 1) == 1) {return false;}for (int i = 0; i < len; i++) {char c = s.charAt(i);if (c == '(') {stack[top++] = ')';} else if (c == '[') {stack[top++] = ']';} else if (c == '{') {stack[top++] = '}';} else {if (top == 0 || stack[--top] != c) {return false;}}}return top == 0;}
}

394. Decode String[Medium]

思路:一般存在遞歸嵌套的結構都首先想到棧,這里棧需要維護兩個值,一個是前序字母序列,還有一個就是需要重復的次數。然后用一個變量實時維護當前字符串,另一個變量將重復次數從字符串轉換為數字。于是操作就變得很清晰了,如果遇到字母或者數字,就維護兩個特定的變量。每次遇到左括號時,將維護的字符串和重復次數加入棧內,并將兩個變量清空。每次遇到右括號時,則將棧頂元素出棧,獲得前序字母序列和重復次數。于是將當前維護的字符串變量重復特定次數后加上前序字母序列,組成新的字符串再維護到當前變量中。

/*
Author Owen_Q
*/
public class StringDecoder {private static class DecoderNode {int count;StringBuffer str;DecoderNode next;public DecoderNode(int count, StringBuffer str, DecoderNode next) {this.count = count;this.str = str;this.next = next;}}public static String decodeString(String s) {int len = s.length();StringBuffer st = new StringBuffer();int cnt = 0;DecoderNode stack = null;for (int i = 0; i < len; i++) {char c = s.charAt(i);if (c <= '9' && c >= '0') {cnt = cnt * 10 + c - '0';} else if (c == '[') {stack = new DecoderNode(cnt, st, stack);st = new StringBuffer();cnt = 0;} else if (c == ']') {if (stack == null) {throw new RuntimeException("stack is empty");}int stackCount = stack.count;for (int j = 0; j < stackCount; j++) {stack.str.append(st);}st = stack.str;stack = stack.next;} else {st.append(c);}}return st.toString();}
}

用鏈表維護棧是真的好用,效率直接拉滿

多想一下:轉棧為DFS

有句話叫dfs問題都可以轉化為棧問題,那么這題其實就是典型的dfs轉化而來的棧,那么復原用dfs實現一下試試

/*
Author Owen_Q
*/
public class StringDecoder {public static String decodeStringWithDfs(String s) {return dfs(s, 0).getValue().toString();}private static Pair<Integer, StringBuffer> dfs(String s, int pos) {StringBuffer st = new StringBuffer();int cnt = 0;int len = s.length();while (pos < len) {char c = s.charAt(pos);if (c <= '9' && c >= '0') {cnt = cnt * 10 + c - '0';} else if (c == '[') {Pair<Integer, StringBuffer> pair = dfs(s, pos + 1);StringBuffer stackStr = pair.getValue();for (int j = 0; j < cnt; j++) {st.append(stackStr);}cnt = 0;pos = pair.getKey();} else if (c == ']') {return new Pair<>(pos, st);} else {st.append(c);}pos++;}return new Pair<>(cnt, st);}
}

?84. Largest Rectangle in Histogram[Hard]

思路:求直方圖的最大矩形區域,這個和當年阿里面試題簡直有異曲同工之妙。最大01子矩陣問題(單調棧優化)_01最大子矩陣-CSDN博客

在原有單調棧求下一個最小值(最大值的變種)基礎上,要分別求元素的前后方的最小值。

再回憶一下單調棧。針對每個位置,會將棧中所有更大的數全都出站,那么此時棧定元素就是下一個更小的數。接下來要求上一個更小的數。我們再繼續思考出入棧的過程,剛剛說到,此時將當前數入棧,那么當前數再次出棧的時候棧頂元素一定還是下一個更小的數。而恰巧,當前數出棧的時候,就說明了上一個更小的數出現了,因為只有更小的數才能驅使棧內元素出棧。總結而言,當棧內元素出棧時,當前元素是出棧元素的上一個更小元素,出棧后的棧頂元素是出棧元素的下一個更小的元素。

再總結一下,針對單調棧,如果只需要求下一個更小元素,可以在枚舉位置處獲取到。但如果想知道上一個更小元素,則需要等到元素出棧后才能獲取到

/*
Author Owen_Q
*/
public class LargestHistogramRectangle {public static int largestRectangleArea(int[] heights) {int len = heights.length;int[] stack = new int[len];int top = -1;int result = 0;for (int i = len - 1; i >= 0; i--) {while (top >= 0 && heights[i] <= heights[stack[top]]) {int now = heights[stack[top]];top--;int width = top == -1 ? len - i - 1 : stack[top] - i - 1;result = Math.max(result, width * now);}stack[++top] = i;}while (top >= 0) {int now = heights[stack[top]];top--;int width = top == -1 ? len : stack[top];result = Math.max(result, width * now);}return result;}
}

完美

完結撒花

?

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

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

相關文章

PIXHAWK(ardupilot4.52)NMEA的解析bug

最近在測試過程中發現在橢球高為負的地方&#xff0c;地面站讀取GPS_RAW_INT (24)消息中的alt高度竟然是正值。而消息中定義的alt并不是一個unsigned數據&#xff0c;理論上是帶有正負符號的。 查看gga的原始信息&#xff1a; $GPGGA,063718.40,3714.8533856,N,11845.9411766,…

Linux容器講解以及對應軟件使用

一、容器基礎知識講解 1.1 微服務的部署策略 部署單體應用意味著運行大型應用的多個相同副本&#xff0c;通常提供若干臺&#xff08;N&#xff09;服務器&#xff08;物理機或虛擬 機&#xff09;&#xff0c;在每臺服務器上運行若干個&#xff08;M&#xff09;應用實例。部…

企業級應用技術-ELK日志分析系統

目錄 #1.1ELK平臺介紹 1.1.1ELK概述 1.1.2Elasticsearch 1.1.3Logstash 1.1.4Kibana #2.1部署ES群集 2.1.1基本配置 2.1.2安裝Elasticsearch 2.1.3安裝Logstash 2.1.4Filebeat 2.1.5安裝Kibana 1.1ELK平臺介紹 1.1.1ELK概述 ELK 是三個開源工具的縮寫&#xff0c;分別是Elas…

Shiro漏洞復現

Shiro簡介 Apache Shiro是一種功能強大且易于使用的Java安全框架&#xff0c;它執行身份驗證、授權、 加密和會話管理&#xff0c;可用于保護任何應用程序的安全。 Shiro提供了應用程序安全性API來執行以下方面&#xff1a; 1.身份驗證&#xff1a;證明用戶身份&#xff0c;通…

VSCode 中使用 Google Test(GTest)框架測試

VSCode 中使用 Google Test&#xff08;GTest&#xff09;框架在 VSCode 中對 C 代碼進行測試的示例&#xff1a; 一、Unbutu x86使用gtest 環境配置 安裝 GTest &#xff1a;在 Ubuntu 系統中&#xff0c;可以通過命令sudo apt-get install libgtest-dev安裝 GTest 庫。對于…

【1.6 漫畫數據庫設計實戰 - 從零開始設計高性能數據庫】

1.6 漫畫數據庫設計實戰 - 從零開始設計高性能數據庫 &#x1f3af; 學習目標 掌握數據庫表結構設計原則理解字段類型選擇與優化學會雪花算法ID生成策略掌握索引設計與優化技巧了解分庫分表設計方案 &#x1f4d6; 故事開始 小明: “老王&#xff0c;我總是不知道怎么設計數…

OSPF虛擬鏈路術語一覽:快速掌握網絡路由

大家好&#xff0c;這里是G-LAB IT實驗室。今天帶大家了解一下OSPF的相關知識&#xff01; 01 OSPF虛擬鏈路術語大全 網絡架構中&#xff0c;OSPF&#xff08;開放式最短路徑優先&#xff09;是一種重要的路由協議。通過其鏈路狀態路由機制&#xff0c;OSPF能夠有效維護和更新…

oracle常用的函數(一) 之 to_char、to_date

文章目錄 前言to_char基本語法格式模型格式模型介紹無FM示例使用FM輸出貨幣負數輸出尖括號 將日期格式化將數字格式化為帶有貨幣符號和千位分隔符的格式總結 to_date語法語法示例 戳這里&#xff0c;第二彈 → oracle常用的函數&#xff08;二&#xff09; 之 nvl、decode、l…

數據庫服務器宕機的處理方法與實戰策略

在當今數字化時代,數據庫作為企業數據存儲與管理的核心,承載著業務運行的關鍵信息。一旦數據庫服務器宕機,將導致業務中斷、數據丟失等嚴重后果,甚至可能給企業帶來巨大的經濟損失和聲譽損害。因此,掌握一套系統、科學的數據庫服務器宕機處理方法尤為重要。本文將從應急響…

如何hack邊緣的kubelet修改Cgroup數值

之前做了一個VPA項目的需求&#xff0c;就是需要不重啟的方式修改容器的Cgroup的值已達到垂直擴縮容的目的&#xff0c;項目中核心的思路如下 上游下發要VPA的結果的值寫入到容器的Annotation里面Kubelet 感知到這個 annoation 的變化我們本地運行一個 Agent&#xff0c;里面運…

熟悉 PyCharm

界面 我們常用的就這個幾個地方&#xff1a; 常用配置 調整字體大小 Ctrl 滾輪調整字體大小 插件推薦 Indent Rainbow 該插件的作用在于能夠對于不同層級縮進的空格標注不同的顏色&#xff1a; 快捷鍵 快捷鍵的 pdf 下載鏈接&#xff1a; Windows 版&#xff1a;https:…

pytorch--模型訓練的一般流程

文章目錄 前言0、數據集準備1、數據集2、dataset3、model4、訓練模型 前言 在pytorch中模型訓練一般分為以下幾個步驟&#xff1a; 0、數據集準備 1、數據集讀取&#xff08;dataset模塊&#xff09; 2、數據集轉換為tensor&#xff08;dataloader模塊&#xff09; 3、定義模型…

智能合同管理實戰:基于區塊鏈的電子簽約技術實現

在數字經濟時代,傳統紙質合同簽署方式已難以滿足企業高效、安全、合規的業務需求。智能合同管理(Smart Contract Management)結合區塊鏈技術,正在重塑電子簽約流程,實現合同全生命周期的自動化、可追溯和防篡改。本文將深入探討基于區塊鏈的電子簽約技術實現,涵蓋核心架構…

設計模式精講 Day 22:模板方法模式(Template Method Pattern)

【設計模式精講 Day 22】模板方法模式&#xff08;Template Method Pattern&#xff09; 文章標簽 設計模式, 模板方法模式, Java開發, 面向對象設計, 軟件架構, 設計模式實戰, Java應用開發 文章簡述 模板方法模式是一種行為型設計模式&#xff0c;它通過定義一個算法的骨架…

如何在pytorch中使用tqdm:優雅實現訓練進度監控

文章目錄 為什么需要進度條&#xff1f;tqdm 簡介基礎用法示例深度學習中的實戰應用1. 數據加載進度監控2. 訓練循環增強版3. 驗證階段集成 高級技巧與最佳實踐1. 自定義進度條樣式2. 嵌套進度條&#xff08;多任務&#xff09;3. 分布式訓練支持4. 與日志系統集成 性能優化建議…

Linux中的xxd命令詳解

xxd 是一個 十六進制轉儲&#xff08;hex dump&#xff09;工具&#xff0c;通常用于將二進制文件轉換為十六進制格式&#xff0c;或者反向轉換&#xff08;十六進制→二進制&#xff09;。它是 vim 的一部分&#xff0c;但在大多數 Linux 系統&#xff08;如 Ubuntu&#xff0…

磐維數據庫panweidb3.1.0單節點多實例安裝

0 說明 業務科室提單需要在某臺主機上部署多個單機磐維數據庫&#xff0c;用于業務測試。以下內容展示如何在單節點安裝多個磐維數據庫實例。 1 部署環境準備 1.1 IP 地址及端口 instipport實例1192.168.131.1717700實例2192.168.131.1727700 在131.17上分別安裝兩個實例&…

轉錄組分析流程(三):功能富集分析

我們的教程主要是以一個具體的例子作為線索,通過對公共數據庫數據bulk-RNA-seq的挖掘,利用生物信息學分析來探索目標基因集作為某種疾病數據預后基因的潛能及其潛在分子機制,同時在單細胞水平分析(對scRNA-seq進行挖掘)預后基因的表達,了解細胞之間的通訊網絡,以期為該疾病…

全面掌握 tkinter:Python GUI 編程的入門與實戰指南

在自動化、工具開發、數據可視化等領域&#xff0c;圖形用戶界面&#xff08;GUI&#xff09;往往是提升用戶體驗的重要方式。作為 Python 官方內置的 GUI 庫&#xff0c;tkinter 以其輕量、跨平臺、易于學習的特性成為初學者和輕量級應用開發者首選。 本文將以深入淺出的方式…

TDH社區開發版安裝教程

&#xff08;注&#xff1a;本文章來源于星環官網安裝手冊&#xff09; 后面放置了視頻和安裝手冊連接 1、硬件及環境要求 Docker17及以上版本&#xff0c;支持Centos&#xff0c;Ubuntu等系統&#xff08;注&#xff1a;這里我使用CentOS-7版本&#xff0c;最佳版本推薦為7.…