leetcode_42 接雨水

1. 題意

給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之后能接多少雨水。

2. 題解

這個題不會做,全部是看得題解捏。

不過能看懂題解感覺自己也很棒了!

看完題解后感覺最難的是如何求出有多少積水,

答案直接給的是當前位置的積水量是它左右兩邊兩個最大值的最小值

減去當前的高度。

靈茶山艾府的題解中解釋了為什么?如果比兩端最高的高積水肯定會

從一側流出去。

不過我肯定是想不到的。

有了這個結論之后,其實就可以做一下了。

對于每個高度,求出它左右兩側的最高高度,從而計算積水的高度。

2.1 前后綴最大值

算出前后綴的最高高度。

再遍歷一次計算積水量。

class Solution {
public:int trap(vector<int>& height) {int n = height.size();int ans = 0;vector<int> left_max(n, 0);vector<int> right_max(n, 0);for (int i = 1; i < n; ++i) {left_max[i] = max(left_max[i - 1], height[i - 1]);}for (int i = n - 2; ~i; --i) {right_max[i] = max(right_max[i + 1], height[i + 1]);}for (int i = 1; i < n - 1; ++i) {ans += max(0, min(left_max[i], right_max[i]) - height[i] );}return ans;}
};

當然可以稍微優化下空間,不過差別不大。

class Solution {
public:int trap(vector<int>& height) {int n = height.size();int ans = 0;vector<int> rightMx(n + 1, -1);for (int i = n - 1; ~i; --i) {rightMx[i] = max(height[i], rightMx[i + 1]);}int leftMx = height[0];for (int i = 1; i < n - 1; ++i) {ans += max( 0, min(leftMx, rightMx[i + 1]) - height[i]);leftMx = max(height[i], leftMx);}return ans;}
};

時間復雜度O(n)O(n)O(n)

空間復雜度O(n)O(n)O(n)

2.2 雙指針

雙指針的解法確實比較巧妙,先說下做法,再證明為什么正確,最后給出代碼。

思路是,左指針lll指向左端,右指針rrr指向右端,同時維護兩個變量:

leftMaxleftMaxleftMax表示lll左端的最大值,

rightMaxrightMaxrightMax表示rrr右端的最大值。

leftMax<rightMaxleftMax <rightMaxleftMax<rightMax時,

左指針元素積水高度為leftMax?height[l]leftMax -height[l]leftMax?height[l],左指針右移。

leftMax≥rightMaxleftMax \ge rightMaxleftMaxrightMax時,

右指針元素積水高度為rightMax?height[r]rightMax - height[r]rightMax?height[r],右指針左移。

為什么這個策略正確呢? 下面簡要證明。

我們令lmx(i)=max?{height[k],0≤k≤i}lmx(i) = \max\{height[k] , 0 \le k \le i\}lmx(i)=max{height[k],0ki}

也就是lmx(i)lmx(i)lmx(i)表示下標iii左端的最大值。

我們令rmx(i)=max?{height[k],i≤k≤n?1}rmx(i)=\max\{ height[k],i \le k \le n-1\}rmx(i)=max{height[k],ikn?1},

也就是rmx(i)rmx(i)rmx(i)表示下標iii右端的最大值。

我們令w[i]w[i]w[i]表示位置iii的積水高度,

那么w[i]=min?(lmx(i),rmx(i))?height[i]w[i] =\min(lmx(i),rmx(i))-height[i]w[i]=min(lmx(i),rmx(i))?height[i]

l≤rl \le rlr時,我們很容易得到

lmx(l)≤lmx(r)rmx(l)≥rmx(r)lmx(l) \le lmx(r)\\ rmx(l) \ge rmx(r) lmx(l)lmx(r)rmx(l)rmx(r)

上面的leftMaxleftMaxleftMax相當于lmx(l)lmx(l)lmx(l)rightMaxrightMaxrightMax相當于rmx(r)rmx(r)rmx(r)

lmx(l)<rmx(r)lmx(l) < rmx(r)lmx(l)<rmx(r)時,必然有lmx(l)<rmx(r)≤rmx(l)lmx(l) < rmx(r) \le rmx(l)lmx(l)<rmx(r)rmx(l)

因此min?(lmx(l),rmx(l))=lmx(l)\min(lmx(l), rmx(l))=lmx(l)min(lmx(l),rmx(l))=lmx(l)

同理lmx(l)≥rmx(r)lmx(l) \ge rmx(r)lmx(l)rmx(r)時,必然有rmx(r)≤lmx(l)≤lmx(r)rmx(r) \le lmx(l) \le lmx(r)rmx(r)lmx(l)lmx(r)

因此min?(lmx(r),rmx(r))=rmx(r)\min( lmx(r), rmx(r)) = rmx(r)min(lmx(r),rmx(r))=rmx(r)

綜上,這個策略是正確的。

下面給出不那么重要的代碼:

class Solution {
public:int trap(vector<int>& height) {int n = height.size();int ans = 0;int l = 0;int r = n - 1;int leftMax = 0;int rightMax = 0;while (l <= r) {leftMax = max( leftMax, height[l]);rightMax = max( rightMax, height[r]);if ( height[l] < height[r]) {ans += leftMax - height[l];++l;}else {ans += rightMax - height[r];--r;}}return ans;}
};

時間復雜度O(n)O(n)O(n)

空間復雜度O(1)O(1)O(1)

2.3 單調棧

說實話不是很明白單調棧的做法怎么想到的,

它比前后綴的做法要難理解的多,也不知道怎么來的,純純為了

用一下這個數據結構?

核心思想是逐步填充積水高度。

當棧頂元素大于新元素時,直接將新元素入棧。

否則,將棧頂元素出棧,令為kkk

將積水高度填充到與新棧頂leftleftleft或新元素height[i]height[i]height[i]的最小值,

min?(height[i],height[left])?height[k]\min(height[i], height[left]) -height[k]min(height[i],height[left])?height[k]

填充的寬度就是i?left?1i-left-1i?left?1

不斷重復這個過程直到棧空或者棧頂大于新元素,再將新元素入棧。

敘述起來很復雜,還是看下圖吧,像個一步步填坑的過程。

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

下面給出代碼

class Solution {
public:int trap(vector<int>& height) {int n = height.size();stack<int> s;int ans = 0;for (int i = 0; i < n; ++i) { while (!s.empty() && height[s.top()] <= height[i]) {int k = s.top();s.pop();if (!s.empty()) {int left = s.top();ans += ( i - left - 1 ) * (min(height[i], height[left]) - height[k] );}}s.push( i );}return ans;}
};

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

3. 參考

leetcode
0x3f

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

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

相關文章

Spring Boot 整合 Thymeleaf 模板引擎:從零開始的完整指南

引言&#xff1a;為什么選擇 Thymeleaf&#xff1f; Thymeleaf 是一個現代化的服務器端 Java 模板引擎&#xff0c;專為 Web 開發而設計。與 JSP 不同&#xff0c;Thymeleaf 模板是純 HTML 文件&#xff0c;可以直接在瀏覽器中預覽&#xff0c;無需后端服務器支持。這種"…

pytest介紹(python測試框架)(@pytest.mark.parametrize、@pytest.fixtures)

文章目錄**1. 核心特點**- **簡潔易用**&#xff1a;無需復雜的配置&#xff0c;只需編寫簡單的函數或類即可進行測試。- **豐富的斷言**&#xff1a;直接使用 Python 內置的 assert 語句&#xff0c;失敗時提供詳細的錯誤信息。- **自動發現測試**&#xff1a;通過約定的命名規…

[Python 基礎課程]繼承

在 Python 的面向對象編程&#xff08;OOP&#xff09;中&#xff0c;繼承&#xff08;Inheritance&#xff09; 是一種重要的機制&#xff0c;它允許一個類&#xff08;稱為子類或派生類&#xff09;從另一個類&#xff08;稱為父類、基類或超類&#xff09;中繼承屬性和方法。…

QT之設計器組件功能(8大類55個組件)

組件名稱 功能描述關鍵屬性1. Layouts&#xff08;布局組件&#xff09;(1) Vertical Layout&#xff08;垂直布局&#xff09;將子控件按垂直方向依次排列layoutSpacing&#xff1a;控件之間的間距layoutMargin&#xff1a;布局邊緣的邊距layoutStretch&#xff1a;設置各控件…

java中list的api詳細使用

在Java中&#xff0c;List是集合框架中最常用的接口之一&#xff0c;繼承自Collection&#xff0c;代表有序、可重復的元素集合&#xff08;允許null元素&#xff09;。其核心實現類有ArrayList&#xff08;數組實現&#xff0c;隨機訪問高效&#xff09;、LinkedList&#xff…

Azure AI Search 探索總結

Azure AI Search 原名 Azure Cognitive Service&#xff0c;是Azure中用來給AI項目構建知識庫的組件。知識庫本質和數據庫很像&#xff0c;但是內部的存儲結構和檢索算法不一樣。比如并不是知識庫的每一列都可以用來過濾、檢索或group by&#xff0c;而是要根據實際情況配置。A…

高效解決 pip install 報錯 SSLError: EOF occurred in violation of protocol

高效解決 pip install 報錯 SSLError: EOF occurred in violation of protocol 標簽&#xff1a; Python, pip, SSLError, Clash, 網絡代理, 問題解決 一、問題描述 在Python開發中&#xff0c;pip 是我們最親密的伙伴。然而&#xff0c;當你身處需要科學上網的環境&#xff0c…

CSS 核心知識點全解析:從基礎到實戰應用

大家好&#xff01;今天這篇文章將系統總結 CSS 的核心知識點&#xff0c;從最基礎的樣式引入到復雜的選擇器應用&#xff0c;再到盒子模型、文本處理等實戰技巧&#xff0c;全程結合代碼示例&#xff0c;讓你輕松掌握 CSS 的精髓。一、CSS 是什么&#xff1f;為什么需要它&…

ClickHouse的學習與了解

什么是ClickHouse&#xff1f; ClickHouse是一個用于聯機分析(OLAP)的列式數據庫管理系統(DBMS)。 在傳統的行式數據庫系統中&#xff0c;數據按如下順序存儲&#xff1a;RowWatchIDJavaEnableTitleGoodEventEventTime#0893543506621Investor Relations12016/5/18 5:19#1903295…

安卓11 12系統修改定制化_____修改系統 解鎖system分區 去除data加密 自由刪減系統應用

在定制化系統中。修改系統分區 解鎖system。讓用戶可以自由刪減應用。這個在定制化服務中比較常見。對于此項修改服務。需要我們了解基礎的分區常識以及常用的幾種基礎修改步驟。 通過博文了解?????? 1??????-----修改rom 解鎖 system 分區有什么意義 2????…

JetPack系列教程(八):PDF庫——讓Android應用也能優雅“翻頁”

JetPack系列教程&#xff08;八&#xff09;&#xff1a;PDF庫——讓Android應用也能優雅“翻頁” 在Android開發的世界里&#xff0c;加載PDF文件一直是個讓人又愛又恨的“小妖精”。愛它&#xff0c;因為PDF是文檔界的“萬能鑰匙”&#xff1b;恨它&#xff0c;因為原生Andr…

Three.js三大組件:場景(Scene)、相機(Camera)、渲染器(Renderer)

上一篇中我們學習了第一個Three.js場景"Hello World"。這一篇就來學習three.js的核心組件。 此圖來源&#xff08;Three.js中文網&#xff09; three.js的核心由三大組件構成&#xff1a;場景(Scene)、相機(Camera)和渲染器(Renderer)。下面我將詳細介紹這三大件的作…

AI幻覺終結之后:GPT-5開啟的“可靠性”新賽道與開發者生存指南

摘要&#xff1a; Sam Altman關于GPT-5將基本終結幻覺的宣告&#xff0c;不僅僅是一次技術升級&#xff0c;它標志著一個“萬物皆可AI&#xff0c;但萬事皆需驗證”的混亂時代的結束。本文將從一個全新的戰略視角出發&#xff0c;探討當“可靠性”取代“創造性”成為AI競賽的核…

ubuntu遠程桌面很卡怎么解決?

服務端方案 完成XRDP的性能優化配置&#xff1a; 1. 首先檢查當前的xrdp.ini文件 grep -n "tcp_send_buffer_bytes" /etc/xrdp/xrdp.ini2. 編輯xrdp.ini文件&#xff0c;修改TCP發送緩沖區大小 sudo sed -i s/#tcp_send_buffer_bytes32768/tcp_send_buffer_bytes4194…

[Linux] Linux系統負載監控 Linux服務管理

目錄 Linux系統負載監控 系統負載介紹 查看系統負載 負載解讀 top 命令 Linux服務管理 systemd 介紹 系統啟動管理進程 基本概念 systemd 架構 unit 類型 查看 unit 列表信息 查看單個 unit 信息 控制系統服務 systemctl 命令 unit 配置文件 例&#xff1a;開發…

vector 手動實現 及遇到的各種細節問題

之前對vector的一些功能使用了一下 接下來手動實現一下vector vector的實現和string還是有不小區別的 有很多地方都有細節的問題不同于string的成員變量一個指針一個size一個capacity的成員變量 vector里面存的是三個迭代器iterator 這的迭代器其實就是模版T的指針 這樣就…

OpenStack Neutron中的L2 Agent與L3 Agent:新手友好指南

引言&#xff1a;云網絡的幕后英雄 在當今的云計算世界中&#xff0c;OpenStack作為開源云平臺的佼佼者&#xff0c;為成千上萬的企業提供了靈活、可擴展的基礎設施服務。而在OpenStack的眾多組件中&#xff0c;Neutron&#xff08;網絡服務&#xff09;扮演著至關重要的角色—…

【自用】JavaSE--特殊文件Properties與XML、日志技術

特殊文件概述使用特殊文件可以存儲多個有關系的數據&#xff0c;作為系統的配置信息屬性文件類似于鍵值對&#xff0c;一一對應存儲數據(比如用戶名與密碼)XML文件存儲多個用戶的多個屬性更適合&#xff0c;適合存儲更復雜的數據Properties注&#xff1a;這個屬性文件的后綴即使…

中本聰思想與Web3的困境:從理論到現實的跨越

一、中本聰思想的核心精髓中本聰通過比特幣白皮書提出的核心思想&#xff0c;可歸納為三大支柱&#xff1a;去中心化貨幣體系目標&#xff1a;擺脫中央機構控制&#xff0c;避免通貨膨脹和政治干預&#xff08;如2008年金融危機暴露的中心化風險&#xff09;。實現路徑&#xf…

Centos 用戶管理

一.創建用戶 在 root賬戶 或 sudo 權限下 1. 創建用戶 useradd xiaoyangzi2.為該用戶設置密碼或修改密碼 passwd xiaoyangzi3. 將用戶加入wheel用戶組 在 CentOS 中&#xff0c;屬于 wheel 組的用戶默認可以使用 sudo 權限。 查看所屬用戶組: groups xiaoyangzi將 xiaoyangzi 加…