LeetCode42(接雨水)[三種解法:理解動態規劃,雙指針,單調棧]

接雨水

給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之后能接多少雨水。
在這里插入圖片描述
在這里插入圖片描述
這是一道困難題,難度確實有點層次.我們先來樸素思想走一波.
要求能接多少雨水,我們可以具化到每個硅谷,每個硅谷能存多少雨水,那么答案就是每個硅谷的雨水所加之和.
對于每一個高度的柱子,我們要求出它的積水量,是等于它左邊高度的最大值與右邊高度的最大值中這兩個值其中的小值減去當前硅谷的高度.
公式為:
在這里插入圖片描述在這里插入圖片描述

怎么理解這句話呢?為什么不是這個硅谷兩旁的高度相比較較小值減去當前硅谷的高度,而是其左右兩邊的最大值呢.

對于這一小塊,我們觀察到積水處的左右兩邊好像跟我們拿其左右兩邊最大值與它身邊兩個的最小值所取到的積水處的值是一樣的.
在這里插入圖片描述

我們仔細來看看中間那部分.
在這里插入圖片描述
這一部分如果取兩邊的值,我們將會漏掉上方那一個單位的正方形值,所以對于積水處的兩旁界限我們應該是選取左右兩邊的最大值.

而為什么又要減去積水處的高度呢?我們再來看下面這一部分
在這里插入圖片描述
其實不用我解釋,現在看這幅圖大家都能理解啦,我們肯定是需要減去它的基礎高度值,才能求得實際上空的空間.也就是硅谷的面積.

所以基于這種求值的思路,我們開始來正式解題.

暴力法解題

我們談到是要取一個硅谷點的左右兩邊最大值來求值.那么每當我們到達一個結點處,遍歷它的左右兩邊找到其左右的最大值就可以完成這一步驟的計算.但由于每一個結點我們都需要遍歷一遍數組,所以時間復雜度為O(2)
我相信大家應該都可以基于暴力能自主完成,這里不做代碼解釋,下面才是算法重點.

動態規劃

我們談到一個節點的左右兩邊的最大值.我們可不可以在計算之前,統計好每一個結點的左右兩邊的最大值.
也就是從左往右開始遍歷,我們可以求得每個結點右邊的最大值.
rightMax[i]=max(rightMax[i+1],height[i])
同理,從右往左遍歷,我們可以求得每個結點左邊的最大值.
leftMax[i]=max(leftMax[i?1],height[i])
總之就是在遍歷計算前,我們打表把所有每個結點的左右兩邊的最大值存儲好,之后我們要求時直接從打表過后的數組里面取就可
代碼為

public int dpMethod(int[] height){int[] leftdp = new int[height.length];int[] rightdp = new int[height.length];int leftMax = 0;int rifhtMax = 0;int res = 0;for(int i = 0;i < height.length;i++){leftdp[i] = leftMax = Math.max(height[i],leftMax);}for(int i = height.length-1;i >= 0;i--){rightdp[i] = rifhtMax = Math.max(height[i],rifhtMax);}for(int i = 0;i < height.length;i++){res += Math.min(leftdp[i],rightdp[i]) - height[i]; }return res;}

時間復雜度為O(n)

單調棧

我們發現硅谷處其實也就是發生破壞一個柱子的單調性時,產生了硅谷.我們可以利用這樣一個特性完成題目的解題.對于每一個結點的索引,我們存放于棧中,每當這個結點的高度小于棧頂元素的值(也就是需要循環遍歷),我們就將其索引值放于棧中.而遇到破壞單調性,也就是一個柱子的高度大于我們的棧頂元素時.我們將棧頂元素彈出,求得此時硅谷處的值.
公式也就是
res += Min(height[peek],height[i])-height[pop]
在這里插入圖片描述
需要注意的是

我們應該在棧中無元素時,不用再進行求值,因為此時說明是邊界情況,對應此時紅框中的情況,當我們計算完pop處之后,下一次循環,我們將彈出peek處的元素,此時它的左邊沒有元素,也就是對應著此時棧中沒有元素.我們不需要再進行求值.

還有一點不同的是,我們遍歷處的height[j] 與我們的棧頂元素是有一段寬度的,我們計算面積應該帶上寬度的乘積,及寬度長度為 i - peek - 1,對應的情況為
在這里插入圖片描述

代碼為

public int stack(int[] height){LinkedList<Integer> rain = new LinkedList();int res = 0;for(int i = 0;i < height.length;i++){while(!rain.isEmpty() && height[rain.peek()] < height[i]){int pop = rain.pop();//彈出棧頂元素if(rain.isEmpty()){break;}int left = rain.peek();//獲取棧頂元素的值,還在棧中沒有彈出int h = Math.min(height[i],height[left]) - height[pop];res += h * (i - left - 1);}rain.push(i);}return res;}

時間復雜度為O(n).

雙指針

最后一種解法就是我們的雙指針啦,也是最快的解法.不需要開辟任何空間,只需要常量級別的空間,而且只需要一次遍歷即可完成.

注意到下標 i 處能接的雨水量由 leftMax[i] 和 rightMax[i] 中的最小值決定。由于數組 leftMax 是從左往右計算,數組 rightMax 是從右往左計算,因此可以使用雙指針和兩個變量代替兩個數組。
遍歷過程中,我們更新左右兩端的最大值.
當左邊的值小于右邊的值時,我們直接拿著左邊的最大值減去當前結點的高度即可.欸?為什么這里我們不需要再次比較左右兩端的最大值,選取其中的較小值呢?
注意啦,我們先判斷左邊的元素是否大于右邊的元素,如果大于我們挪動的是右指針,也就是說明如果右邊的值沒有大于過左邊的值,將一直挪動的是右指針,間接性的把左右兩端的最大值作了比較.
右邊的值小于左邊的值是也是如此.

代碼為所以

public int trap(int[] height) {int left = 0;int right = height.length - 1;int leftMax = 0;int rightMax = 0;int res = 0;while(left < right){leftMax = Math.max(leftMax,height[left]);rightMax = Math.max(rightMax,height[right]);if(height[left] < height[right]){res += leftMax - height[left];left++;}else{res += rightMax - height[right];right--;}}return res;}

時間復雜度為O(n),空間復雜度為O(1)

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

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

相關文章

PDA:Prompt-based Distribution Alignment for Unsupervised Domain Adaptation

文章匯總 式中&#xff0c; y s y^s ys表示源域數據的one-hot ground-truth&#xff0c; K K K為類數&#xff0c; w i w_i wi?和 z ~ s \tilde{z}_s z~s?分別表示源域經過提示調優的最終文本表示和最終圖像表示的第 i i i類。 同理&#xff0c;為了進一步利用目標領域的數據…

防火墻詳解(USG6000V)

0、防火墻組網模式 防火墻能夠工作在三種模式下分別是路由模式、透明模式、旁路檢測模式、混合模式 0.1、路由模式 路由模式&#xff1a;防火墻全部以第三層對外連接&#xff0c;即接口具有IP 地址。一般都用在防火墻是邊界的場景下 防火墻需要的部署/配置&#xff1a; 接…

【入門篇】STM32尋址范圍(更新中)

寫在前面 STM32的尋址范圍涉及存儲器映射和32位地址線的使用。并且STM32的內存地址訪問是按字節編址的,即每個存儲單元是1字節(8位)。 一、尋址大小與范圍 地址線根數 地址編號(二進制) 地址編號數(即內存大小) <

實現基于Elasticsearch的搜索服務

實現基于Elasticsearch的搜索服務 大家好&#xff0c;我是微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 1. Elasticsearch簡介 Elasticsearch是一個開源的分布式搜索引擎&#xff0c;提供強大的全文搜索和分析功能。本文…

10、DDD分層架構

微服務架構模型有很多種&#xff0c;例如洋蔥架構、CQRS和六邊形架構等。雖然這些架構模式提出的時代和背景不同&#xff0c;但其核心理念都是為了設計出“高內聚&#xff0c;低耦合”的微服務&#xff0c;輕松實現微服務的架構演進。DDD分層架構的出現&#xff0c;使微服務的架…

什么是ThreadLocal以及內存泄漏問題、hash沖突問題

ThreadLocal是什么 ThreadLocal類用來提供線程內部的局部變量 它主要有三大特性&#xff1a; 線程安全: 在多線程并發的場景下保證線程安全傳遞數據&#xff1a;通過ThreadLocal在同一線程傳遞公共變量線程隔離&#xff1a;每個線程的變量都是獨立的&#xff0c;不會互相影響…

這次讓我們從幾個點認識一下Mysql的Innodb

MySQL 的 InnoDB 存儲引擎是 MySQL 默認和最常用的存儲引擎之一。它主要關注的是高可靠性、性能以及完整的事務支持。以下是對 InnoDB 存儲引擎的詳細介紹&#xff1a; 1. 數據庫特性 1.1 事務支持 InnoDB 是完全支持事務的存儲引擎&#xff0c;支持四種主要的事務隔離級別&…

【uniapp-ios】App端與webview端相互通信的方法以及注意事項

前言 在開發中&#xff0c;使用uniapp開發的項目開發效率是極高的&#xff0c;使用一套代碼就能夠同時在多端上線&#xff0c;像筆者之前寫過的使用Flutter端和webview端之間的相互通信方法和問題&#xff0c;這種方式本質上實際上是h5和h5之間的通信&#xff0c;網上有非常多…

ios身份證實名認證接口開發示例助力電商物流實名認證

為了更好的利用貨車資源&#xff0c;也方便企業正常的運送貨物&#xff0c;“互聯網電商”平臺可謂風起云涌。貨車司機和有發貨需求的人們可以在物流平臺注冊&#xff0c;貨車司機接單為有運送需求的用戶提供有償貨運服務。那么&#xff0c;如何讓企業放心的將貨物安心的交予貨…

物聯網實訓室建設可行性報告

一、建設物聯網實訓室的目的和意義 隨著信息技術的快速發展&#xff0c;物聯網&#xff08;IoT&#xff09;已成為推動社會進步和經濟發展的關鍵技術之一。物聯網技術的集成應用&#xff0c;不僅能夠提高生產效率&#xff0c;還能促進智慧城市、智能家居、智能農業等多個領域的…

python04——類(基礎new)

類其實也是一種封裝的思想&#xff0c;類就是把變量、方法等封裝在一起&#xff0c;然后可以通過不同的實例化對其進行調用操作。 1.類的定義 class 類名&#xff1a; 變量a def __init__ (self,參數2&#xff0c;參數2...)&#xff1a;初始化函數&#xff01;&#xff01;&…

vivado DELAY_VALUE_XPHY、DIFF_TERM

延遲_值_XPHY PORT對象上的DELAY_VALUE_XPHY屬性指定要添加的延遲量 Versal XPHY邏輯接口的輸入或輸出路徑。在的早期階段 opt_design在重新生成高級I/O向導IP時 DELAY_VALUE_XPHY值將從PORT復制到的XPHY實例上 輸入或輸出路徑。Vivado設計套件中存在DRCs&#xff0c;以確保 DE…

簡單實現聯系表單Contact Form自動發送郵件

如何實現簡單Contact Form自動郵件功能&#xff1f;怎樣簡單設置&#xff1f; 聯系表單不僅是訪客與網站所有者溝通的橋梁&#xff0c;還可以收集潛在客戶的信息&#xff0c;從而推動業務的發展。AokSend將介紹如何簡單實現一個聯系表單&#xff0c;自動發送郵件的過程&#x…

java Collections類介紹

Java 的 java.util.Collections 類提供了一組靜態方法&#xff0c;用于操作或返回集合&#xff08;如列表、集合和映射&#xff09;。Collections 類是一個實用工具類&#xff0c;旨在為集合提供便捷的算法和操作。以下是對 Collections 類及其常用方法的介紹。 常用方法總結 …

【游戲客戶端】大話slg玩法架構(一)滾動基類

【游戲客戶端】大話slg玩法架構&#xff08;一&#xff09;滾動基類 大家好&#xff0c;我是Lampard家杰~~ 今天我們兌現諾言&#xff0c;給大家分享SLG玩法的實現j架構&#xff0c;關于SLG玩法的介紹可以參考這篇上一篇文章&#xff1a;【游戲客戶端】制作率土之濱Like玩法 PS…

保險理論與實踐

《保險理論與實踐》是由中國保險學會主辦的學術集刊&#xff0c;于2016年1月正式創辦&#xff0c;致力于發表權威、嚴謹、高質量的理論研究、政策研究和實務研究成果&#xff0c;強調學術性與政策性、理論性與實踐性的有機結合。本刊由中國金融出版社公開出版&#xff0c;每月下…

postmessage()在同一域名下,傳遞消息給另一個頁面

這里是同域名下&#xff0c;getmessage.html&#xff08;發送信息&#xff09;傳遞消息給index.html&#xff08;收到信息&#xff0c;并回傳收到信息&#xff09; index.html頁面 <!DOCTYPE html> <html><head><meta http-equiv"content-type"…

機器學習統計學基礎 - 最大似然估計

最大似然估計&#xff08;Maximum Likelihood Estimation, MLE&#xff09;是一種常用的參數估計方法&#xff0c;其基本原理是通過最大化觀測數據出現的概率來尋找最優的參數估計值。具體來說&#xff0c;最大似然估計的核心思想是利用已知的樣本結果&#xff0c;反推最有可能…

Java并發編程工具包(JUC)詳解

在現代軟件開發中&#xff0c;多線程編程是一個不可避免的話題。為了更好地管理和利用多線程&#xff0c;Java提供了一個強大的工具包——java.util.concurrent&#xff08;簡稱JUC&#xff09;。JUC包含了許多用于并發編程的類和接口&#xff0c;幫助開發者高效、安全地處理線…

binutils ifunc 流程圖

上圖是x86 binutils 的流程圖。 函數說明_bfd_x86_elf_link_hash_table_createInit local STT_GNU_IFUNC symbol hash.elf_x86_64_check_relocsAdd support for handling STT_GNU_IFUNC symbols_bfd_elf_x86_get_local_sym_hashFind and/or create a hash entry for local sym…