二刷力扣——單調棧

739. 每日溫度

單調棧應該從棧底到棧頂 是遞減的。

找下一個更大的 ,用遞減單調棧,就可以確定在棧里面的每個比當前元素i小的元素,下一個更大的就是這個i,然后彈出并記錄;然后當前元素i入棧,仍然滿足遞減要求。最后留在棧里面的是沒有下一個更大的值的,符合要求。

找下一個更小的用遞增單調棧同理。

result[被彈出下標]=使他彈出下標-被彈出下標。

復習一下Java集合知識:來自Java集合詳解-CSDN博客

LinkedList 可以使用多種接口進行聲明,包括但不限于:

  • Deque 接口:Deque<Integer> deque = new LinkedList<>();: 雙端隊列的操作,包括棧和隊列的功能。
  • Queue 接口:Queue<Integer> queue = new LinkedList<>();: 適合實現隊列的操作,包括 offer、poll、peek 等方法。
  • List 接口:List<Integer> list = new LinkedList<>();: 通用的集合操作,如添加、刪除、獲取元素等。
  • Collection 接口:Collection<Integer> collection = new LinkedList<>();: 這種聲明方式表示通用的集合操作,適合需要簡單地操作元素集合的場景。
class Solution {public int[] dailyTemperatures(int[] temperatures) {int n=temperatures.length;Deque<Integer> stack=new LinkedList<>();//放下標,int [] result =new int[n];for(int i=0;i<n;++i){int temp=temperatures[i];while(!stack.isEmpty() && temperatures[stack.peek()]<temp){int a=stack.pop();//小,被彈出result[a]=i-a;}//找到位置stack.push(i);}return result;}
}

時間、空間O(n)

496. 下一個更大元素 I

跟上一題區別是,先用單調棧把nums2處理,較小的元素彈出來的時候要找到當前元素i在nums1的位置,然后給到result。

這里不算下標而且數組里面沒有重復元素,所以單調棧里面可以放元素值。

另外result一開始都賦值-1。最后可能nums1里有幾個是沒有下一個更大值的。

class Solution {public int[] nextGreaterElement(int[] nums1, int[] nums2) {int m=nums1.length ,n=nums2.length ;Deque<Integer> stack=new LinkedList<Integer>();int[] result=new int[m];HashMap<Integer,Integer> hash=new HashMap<>();// 放元素for(int i=0;i<m;++i){hash.put(nums1[i],i);}for(int i=0;i<m ;++i){result[i]=-1;}for(int i=0;i<n;++i){int tmp=nums2[i];while(!stack.isEmpty() && stack.peek()<tmp){int a=stack.pop();//被彈出的元素aint pos=hash.getOrDefault(a,-1);if(pos!=-1)result[pos]=tmp;}stack.push(tmp);}return result;}
}

時間是O(m+n)。初始化result和hash的是O(m),單調棧循環是O(n),因為用的HashMap,查找O(1)。

503. 下一個更大元素 II

要求循環地搜索元素的下一個更大的數,其實就是單調棧要走兩次nums數組。

class Solution {public int[] nextGreaterElements(int[] nums) {int n=nums.length;int[] result=new int[n];Deque<Integer> stack=new LinkedList<>();Arrays.fill(result,-1);for(int j=0;j<2*n;++j){int i=j%n;int num=nums[i];while(!stack.isEmpty() && nums[stack.peek()]<num){int a=stack.pop();result[a]=nums[i];}stack.push(i);}return result;}
}

42. 接雨水

1、以列為單位,每列都找自己左邊(包含自己)的最高柱子 l 和自己右邊(包含自己)的最高柱子 r,就形成一個凹槽。然后每一列應該裝下的雨水數就應該是(min(l , r) - 自己柱子高)*寬。所以主要關注l 和 r 怎么計算。

1.1、DP

維護一個lefts和rights數組,lefts[i]是l,rights[i]就是r。

那么遞推公式就是:(min(lefts[i] , rights[i]) - 自己柱子高)*寬

關鍵得到這兩個數組,還是很直觀的,lefts涉及到的是i及左邊的,所以從左往右遞推;rights從右往左。

class Solution {public int trap(int[] height) {int n=height.length;int count=0;int[] lefts=new int[n];int[] rights=new int[n];lefts[0]=height[0];for(int i=1;i<n;++i){lefts[i]=Math.max(lefts[i-1],height[i]);}rights[n-1]=height[n-1];for(int i=n-2;i>=0;--i){rights[i]=Math.max(rights[i+1],height[i]);}for(int i=0;i<n;++i){count+=(Math.min(lefts[i],rights[i])-height[i]);}return count;}
}

時間空間:O(n)

1.2、雙指針

用兩個指針left、right從兩端,逐漸逼近,逼近的判斷條件是:left指向的和right指向的對比,哪一方小,就走一步。

①這里對于紅框的判斷不能理解,為什么當前的哪一方小,就能確定這一方的最大值更小呢?

下面這個說法很形象。其實就是A隊B隊比賽,遍歷過了的都是輸了的(或者平局的),假如B隊的curB贏了A隊的curA,所以目前MAX_B(其實就是curB)是目前兩隊最強。即A隊最強的其實是輸給B隊過的了,所以A隊最強不如B隊最強。可以確定MAX_B=curB>MAX_A。A贏B就同理。

②又想:假如B隊贏了A隊,可以確定出現了一個凹槽:A隊最高、curA、B隊最高。這個凹槽的兩端一定是我們要求的嗎?

A隊最高肯定是所要求的左邊最高柱子l ,B隊最高不一定是右邊最高柱子 r。假如curA和curB之間還有比MAX_A更矮的柱子,壓根不考慮因為我們是先找兩端最高的,再在兩個最高的里找最小的;假如有比MAX_B更高的柱子,那取Min值仍然還是MAX_A。A贏B就同理。

總的來說,哪一方輸了,哪一方的輸家就可以確定他的雨水了。決定這個雨水高度的就是他這一方的最強者(但是比另一方的最強者弱)。

可以用MAX_B>MAX_A,用height[a]<height[b]感覺更能體現這個“比賽”的過程吧,當前選手的大小。

class Solution {public int trap(int[] height) {int n=height.length;int a=0,b=n-1;//對手int MAX_A=0,MAX_B=0;//一個隊里面已比對手的最強者int count=0;while(a<b){//更新最強者,要包括當前選手MAX_A=Math.max(MAX_A,height[a]);MAX_B=Math.max(MAX_B,height[b]);int yushui=0;//輸的一方收集雨水if(height[a]<height[b])//b整體贏了{yushui=MAX_A-height[a];//注意凹槽兩端a++;//輸的下場,派下一個}else if(height[a]>=height[b]){yushui=MAX_B-height[b];b--;        }count+=yushui;}return count;}
}

時間O(n)空間O(1)

2、以行為單位

2.1 單調棧

以列為單位求,每個柱子的雨水是一次性求好,需要提前知道左邊最高柱子和右邊最高柱子,這形成凹槽1;

以行為單位求,是求以每個柱子為底的這一行能接的雨水,這一行雨水可以到的高度,應該是最接近自己的柱子的最小高度。即Min(上一個更大,下一個更大)。這是凹槽2。

這是按行求 和 按列求 的主要區別。

這一行,寬是 下一個更大和上一個更大的 下標間隔。高是Min值和中間 a 的差。

class Solution {public int trap(int[] height) {int n=height.length;int count=0;Deque<Integer> stack=new LinkedList<Integer> ();for(int i=0;i<n;++i){int tmp=height[i];while(!stack.isEmpty() && height[stack.peek()]<tmp)//凹槽{int a=stack.pop();//l=棧底,a,r=height[i]if(!stack.isEmpty()){int l=stack.peek();int r=i;int kuan=r-l-1;int gao=Math.min(height[l],height[r])-height[a];count+=kuan*gao;}}stack.push(i);}return count;}
}

84. 柱狀圖中最大的矩形

貌似只能以行為單位,所以只看單調棧方法。

需要找到元素i的上一個更小的元素leftmin和下一個更小的元素rightmin,這樣leftmin和rightmin之間的元素都比當前元素i更大,那么矩形的寬就是中間的這些元素:可以從leftmin+1延伸到rightmin-1,長即為height[i]。

怎么確定矩形的寬 和高?寬有左邊界和右邊界,這里感覺應該每次固定一邊然后討論另一邊。這里固定右邊界,是遍歷的i,也就是對于每個柱子i 都計算,以這個元素為右邊界 ,矩形的最大面積。知道右邊界了,要讓面積最大左邊界應該是多少呢?其實應該找上一個更小值l 。這樣 (l,i) 之間都是比i 高或者相等的柱子,這就是固定i 為右邊界的最大面積。

怎么保證能處理所有元素?使用單調棧,pop一個元素就算這個元素右邊界的矩形。題目說柱子都是>=0的,那么在最后的時候 ,單調棧再插入一個0,就能把棧里面的所有元素都pop出來,就都處理到了

單調棧 的順序 應該是 需要 嚴格單調遞增的。因為棧不為空要找上一個更小值l 。之前的題事實上只在單個>、<的時候要出棧,因為只需要求下一個更大/更小。上面的接雨水也是棧頂=當前的話沒關系,相減是0 沒影響。但是這里得嚴格遞增。

過程是:當 i 元素 <= 棧頂的 a,這個時候這個i 元素就是右邊界,我們要討論單調棧里面所有比這個元素大的元素為高的矩形面積。現在 兩種情況:

1、棧頂a彈出,棧為空了,說明什么?在heights里面,a的左邊沒有比他嚴格小于的l ,都是>=他的,而a 的下一個更小值又是i,所以區間是[0,i-1)所以寬就是i;

2、如果棧不為空,那就是存在l ,這個l 就是a彈出之后的新棧頂(比a 要小的)。所以矩形區間是(新棧頂=l,i)。

class Solution {public int largestRectangleArea(int[] heights) {int n = heights.length;Deque<Integer> stack = new LinkedList<>(); // 存儲柱子的索引int maxArea = 0;for (int i = 0; i <= n; ++i) {int h = (i == n) ? 0 : heights[i]; // 最后加入一個高度為0的柱子,確保處理完所有柱子while (!stack.isEmpty() && heights[stack.peek()] >= h) {int a=stack.pop();int height = heights[a]; // 當前出棧的柱子高度// 計算寬度:是i代表前面i個都是>=height的。否則矩形寬是(上一個更小的,i-1]int width = stack.isEmpty() ? i : i - stack.peek() - 1; maxArea = Math.max(maxArea, height * width);System.out.println(maxArea);}stack.push(i); // 當前柱子的索引入棧}return maxArea;}
}

主要是 :確定一邊求另一邊的思想、求上一個更小值用單調棧、為了處理所有元素添加一個最小值0。

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

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

相關文章

數學基礎 -- 三角學

三角學 三角學&#xff08;Trigonometry&#xff09;是數學的一個分支&#xff0c;主要研究三角形的邊長與角度之間的關系。三角學在幾何學、物理學、工程學等多個領域中有廣泛的應用。以下是三角學的一些基本概念和公式&#xff1a; 基本概念 直角三角形&#xff1a;一個角…

Java進階----繼承

繼承 一.繼承概述 繼承是可以通過定義新的類&#xff0c;在已有類的基礎上擴展屬性和功能的一種技術. 案例&#xff1a;優化 貓、狗JavaBean類的設計 狗類&#xff1a;Dog 屬性&#xff1a;名字 name&#xff0c;年齡 age 方法&#xff1a;看家 watchHome()&#xff0c;Gett…

防抖和字節流

防抖&#xff08;Debouncing&#xff09;和字節流&#xff08;Byte Stream&#xff09;是兩個不同的概念&#xff0c;分別在編程和數據傳輸領域中使用。 防抖&#xff08;Debouncing&#xff09; 防抖是一種在前端開發中常用的技術&#xff0c;用于控制事件處理函數的執行頻率…

Android多開應用軟件系統設計

設計一個支持Android多開應用的軟件系統&#xff0c;主要涉及到以下幾個關鍵技術點和設計考慮&#xff1a; 1. 虛擬化技術 容器技術&#xff1a;與傳統的虛擬機不同&#xff0c;可以采用更輕量級的容器技術&#xff0c;為每個應用實例創建獨立的運行環境。這包括分配獨立的用…

Ubuntu配置sendmail client,用sendmail命令來發送郵件

參考文檔 https://mailoutgoing.com/support/mailrelay/sendmail.html https://www.sendmail.org/~ca/email/auth.html https://docs.oracle.com/en/operating-systems/oracle-linux/6/admin/configure-sendmail.html 總結 1、ubuntu環境下&#xff0c;sendmail服務位于/etc/i…

HTTP 請求走私漏洞詳解

超詳細的HTTP請求走私漏洞教程&#xff0c;看完還不會你來找我。 1. 簡介 HTTP請求走私漏洞&#xff08;HTTP Request Smuggling&#xff09;發生在前端服務器&#xff08;也稱代理服務器&#xff0c;一般會進行身份驗證或訪問控制&#xff09;和后端服務器在解析HTTP請求時&…

上位機圖像處理和嵌入式模塊部署(mcu項目2:串口日志記錄器)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】 淘寶上面有一個商品蠻好玩的&#xff0c;那就是日志記錄器。說是記錄器&#xff0c;其實就是一個模塊&#xff0c;這個模塊的輸入是一個ttl串口&am…

利用Python進行數據分析PDF下載經典數據分享推薦

本書由Python pandas項目創始人Wes McKinney親筆撰寫&#xff0c;詳細介紹利用Python進行操作、處理、清洗和規整數據等方面的具體細節和基本要點。第2版針對Python 3.6進行全面修訂和更新&#xff0c;涵蓋新版的pandas、NumPy、IPython和Jupyter&#xff0c;并增加大量實際案例…

Docker Desktop如何換鏡像源?

docker現在很多鏡像源都出現了問題,導致無法拉取鏡像,所以找到一個好的鏡像源,尤為重要。 一、阿里鏡像源 經過測試,目前,阿里云鏡像加速地址還可以使用。如果沒有阿里云賬號,需要先注冊一個賬號。 地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 二…

基于Java技術的B/S模式書籍學習平臺

你好&#xff0c;我是專注于計算機科學領域的學姐碼農小野。如果你對書籍學習平臺開發感興趣或有相關需求&#xff0c;歡迎私信聯系我。 開發語言&#xff1a; Java 數據庫&#xff1a; MySQL 技術&#xff1a; B/S模式、Java技術 工具&#xff1a; Eclipse、Navicat、Mave…

【Go】函數的使用

目錄 函數返回多個值 init函數和import init函數 main函數 函數的參數 值傳遞 引用傳遞&#xff08;指針&#xff09; 函數返回多個值 用法如下&#xff1a; package mainimport ("fmt""strconv" )// 返回多個返回值&#xff0c;無參數名 func Mu…

相鄰不同數字的標記

鏈接&#xff1a;登錄—專業IT筆試面試備考平臺_牛客網 來源&#xff1a;牛客網 時間限制&#xff1a;C/C 1秒&#xff0c;其他語言2秒 空間限制&#xff1a;C/C 262144K&#xff0c;其他語言524288K 64bit IO Format: %lld 題目描述 小紅拿到了一個數組&#xff0c;每個數…

ctfshow web入門 nodejs web334--web337

web334 有個文件下載之后改后綴為zip加壓就可以得到兩個文件 一個文件類似于index.php 還有一個就是登錄密碼登錄成功就有flag username:ctfshow password:123456因為 return name!CTFSHOW && item.username name.toUpperCase() && item.password passwor…

SpringBoot的熱部署和日志體系

SpringBoot的熱部署 每次修改完代碼&#xff0c;想看效果的話&#xff0c;不用每次都重新啟動代碼&#xff0c;等待項目重啟 這樣就可以了 JDK官方提出的日志框架&#xff1a;Jul log4j的使用方式&#xff1a; &#xff08;1&#xff09;引入maven依賴 &#xff08;2&#x…

軟件開發語言都有哪些?

構建高效、穩定且安全的服務器應用&#xff0c;開發者們需要選擇合適的編程語言。以下是幾種流行的網絡服務器開發語言&#xff0c;每種語言都有其獨特的特性和適用場景。 Java Java是一種廣泛使用的高級編程語言&#xff0c;以其“一次編寫&#xff0c;到處運行”的理念而著稱…

光譜優化算法(Lightning Search Optimization, LSO)及其Python和MATLAB實現

光譜優化算法&#xff08;Lightning Search Optimization, LSO&#xff09;是一種基于自然界雷暴現象啟發的新型優化算法&#xff0c;旨在尋找最優解或近似最優解的問題。LSO算法不僅可以用于連續優化問題&#xff0c;還能用于離散優化問題。接下來將詳細介紹LSO算法的背景、原…

內鏡像源-大全

1、pip安裝鏡像 阿里鏡像 https://developer.aliyun.com/mirror/ 清華大學開源軟件鏡像 https://mirrors.tuna.tsinghua.edu.cn/ 浙大鏡像源 http://mirrors.zju.edu.cn/ 網易鏡像源 https://mirrors.163.com/ sohu鏡像源 https://mirrors.sohu.com/ 中科大鏡像 https://mirr…

OS Copilot測評-CSDN

登錄控制臺 安裝插件 sudo yum install -y os-copilot效果如下 配置 AccessKey ID 與 AccessKey Secret 注意安全&#xff0c;使用完成后&#xff0c;別忘了去控制臺刪除&#xff0c;一般情況使用子Key就可以 檢測是否可用 co hi實際操作(當前為官方案例請求) 實操1&…

RoPE 旋轉位置編碼,詳細解釋(下)NLP 面試的女生徹底說明白了

RoPE 旋轉位置編碼&#xff0c;詳細解釋&#xff08;下&#xff09;NLP 面試的女生徹底說明白了 原創 看圖學 看圖學 2024年07月01日 07:55 北京 書接上文&#xff0c;上文見&#xff1a;這么解釋 RoPE 旋轉位置編碼&#xff0c;女朋友睜大了雙眼&#xff08;上&#xff09; …

C++ explicit 用法

一、概述 explicit關鍵字用于防止構造函數或轉換操作符在不明確的情況下被隱式調用&#xff0c;從而避免意外的類型轉換。這在類的設計中非常有用&#xff0c;可以增強代碼的可讀性和安全性。 二、用法示例 1. 用于構造函數 假設有一個簡單的類 A&#xff1a; class A { p…