Leetcode力扣解題記錄--第42題 接雨水(動規和分治法)

題目鏈接:42. 接雨水 - 力扣(LeetCode)

這里我們可以用兩種方法去解決巧妙地解決這個題。首先來看一下題目

題目描述

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

示例 1:

輸入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
輸出:6
解釋:上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。?

示例 2:

輸入:height = [4,2,0,3,2,5]
輸出:9

提示:

  • n == height.length

  • 1 <= n <= 2 * 104

  • 0 <= height[i] <= 105

題目作答

核心解題思想

????????解決此問題的根本在于,對于數組中的任意一個位置 i,其上方能夠積蓄的雨水高度,取決于它左側所有柱子中的最高者 (left_max) 和右側所有柱子中的最高者 (right_max) 中較矮的那一個。這個較矮的高度決定了該位置的水位。

  • 該位置 i 的最終水位高度為:water_level = min(?left_max, right_max)。
  • 該位置 i 本身能存儲的雨水量為:water[i] = water_level - height[i]。(如果結果為負數,則該處蓄水量為0)

我們的目標就是求出所有位置的蓄水量的值再相加


方法一:動態規劃

此方法通過預計算,直觀地實現了上述核心思想。

思路

  1. 預計算左側最大高度:創建一個數組 left_max_arr,長度與 height 相同。從左到右遍歷 height 數組,對于每個位置 i,left_max_arr[i] 存儲從索引 0 到 i 的所有柱子中的最大高度。
  2. 預計算右側最大高度:創建另一個數組 right_max_arr。這一次,我們從右到左遍歷 height 數組,對于每個位置 i,right_max_arr[i] 存儲從索引 i 到 n-1 的所有柱子中的最大高度。
  3. 計算總雨水量:當我們擁有了每個位置的左側最高和右側最高之后,就可以進行第三次遍歷。對于每個位置 i,其水位就是 min(left_max_arr[i], right_max_arr[i])。用這個水位減去當前柱子的高度 height[i],就是該位置的蓄水量。將所有位置的蓄水量累加起來,即為最終答案。

圖片來源:毒瘤面試題:接雨水_嗶哩嗶哩_bilibili

復雜度分析

  • 時間復雜度: O(n)。我們進行了三次獨立的線性遍歷,總時間復雜度為 O(n)+O(n)+O(n)=O(n)。
  • 空間復雜度: O(n)。我們使用了兩個長度為 n 的額外數組 left_max_arr 和 right_max_arr 來存儲中間計算結果。

代碼如下

class Solution {
public:int trap(vector<int>& height) {int n = height.size();if (n < 3) {return 0;}// 1. left_max_arr 數組,記錄從左到右的最大值vector<int> left_max_arr(n);left_max_arr[0] = height[0];for (int i = 1; i < n; ++i) {left_max_arr[i] = max(left_max_arr[i - 1], height[i]);}// 2. right_max_arr 數組,記錄從右到左的最大值vector<int> right_max_arr(n);right_max_arr[n - 1] = height[n - 1];for (int i = n - 2; i >= 0; --i) {right_max_arr[i] = max(right_max_arr[i + 1], height[i]);}// 3. 遍歷每個位置,計算并累加雨水int total_water = 0;for (int i = 0; i < n; ++i) {// 計算當前位置的水位int water_level = min(left_max_arr[i], right_max_arr[i]);// 累加當前位置的蓄水量total_water += water_level - height[i];}return total_water;}
};

方法二:分治法

此方法是動態規劃解法的空間優化版本,它在一次遍歷中就完成了所有計算,無需額外的存儲數組。

思路

第一步:找到全局最高點

????????首先,我們需要一次遍歷整個 height 數組,找到其中最高的柱子的高度 max_height 和其對應的索引 max_index。這個最高的柱子就像一座山峰,它自然地將整個地形分成了左、右兩個部分。在它左邊的區域,積水情況最多只會受到它本身以及它左邊的墻的影響;同理,右邊的區域也是如此。

第二步:處理左半部分(從數組開頭到最高點)

????????現在,我們從數組的最左邊(索引 0)開始,向右遍歷直到最高點所在的索引 max_index。

  • 我們維護一個變量 left_max,用來記錄從左邊到當前位置為止遇到的最高墻體。
  • 對于這個區間的任何一根柱子 height[i],它右邊的最高墻一定是我們第一步找到的全局最高點 max_height。
  • 因此,在該位置 i 的蓄水高度瓶頸,就完全取決于其左邊的最高墻 left_max。因為 left_max 不可能超過 max_height。
  • 所以,在位置 i 的蓄水量就是 left_max - height[i]。
  • 我們從左向右遍歷,不斷更新 left_max 并累加每個位置的蓄水量。

第三步:處理右半部分(從數組末尾到最高點)

????????處理完左邊,我們用完全對稱的邏輯來處理右半部分。

  • 我們從數組的最右邊(索引 n-1)開始,向左遍歷直到最高點所在的索引 max_index。
  • 我們維護一個變量 right_max,用來記錄從右邊到當前位置為止遇到的最高墻體。
  • 對于這個區間的任何一根柱子 height[i],它左邊的最高墻一定是全局最高點 max_height。
  • 因此,在該位置 i 的蓄水高度瓶頸,就完全取決于其右邊的最高墻 right_max。
  • 我們在遍歷過程中,不斷更新 right_max 并累加每個位置的蓄水量 right_max - height[i]。

將第二步和第三步計算出的蓄水量相加,就得到了最終的總量。

復雜度分析

  • 時間復雜度: O(n)。
  • 空間復雜度: O(1)。
class Solution {
public:int trap(vector<int>& height) {int n = height.size();if (n < 3) {return 0;}// 1. 找到全局最高點int max_height = 0;int max_index = 0;for (int i = 0; i < n; ++i) {if (height[i] > max_height) {max_height = height[i];max_index = i;}}int total_water = 0;// 2. 處理左半部分 (從 0 到 max_index)int left_max = 0;for (int i = 0; i < max_index; ++i) {// 更新左側遇到的最高墻left_max = max(left_max, height[i]);// 計算當前位置的蓄水量并累加total_water += left_max - height[i];}// 3. 處理右半部分 (從 n-1 到 max_index)int right_max = 0;for (int i = n - 1; i > max_index; --i) {right_max = max(right_max, height[i]);total_water += right_max - height[i];}return total_water;}
};

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

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

相關文章

寶塔配置pgsql可以遠程訪問

本地navicat premium 17.0 可以遠程訪問pgsql v16.1寶塔的軟件商店里&#xff0c;找到pgsql管理器&#xff1b;在pgsql管理器里找到客戶端認證&#xff1a;第二步&#xff1a;配置修改&#xff0c;CtrlF 查找listen_addresses關鍵字&#xff1b;第三步&#xff1a;在navicat里配…

小架構step系列12:單元測試

1 概述 測試的種類很多&#xff1a;單元測試、集成測試、系統測試等&#xff0c;程序員寫代碼進行測試的可以稱為白盒測試&#xff0c;單元測試和集成測試都可以進行白盒測試&#xff0c;可以理解為單元測試是對某個類的某個方法進行測試&#xff0c;集成測試則是測試一連串的…

SpringBoot3-Flowable7初體驗

目錄簡介準備JDKMySQLflowable-ui創建流程圖要注意的地方編碼依賴和配置控制器實體Flowable任務處理類驗證啟動程序調用接口本文源碼參考簡介 Flowable是一個輕量的Java業務流程引擎&#xff0c;用于實現業務流程的管理和自動化。相較于老牌的Activiti做了一些改進和擴展&…

phpMyAdmin:一款經典的MySQL在線管理工具又回來了

phpMyAdmin 是一個免費開源、基于 Web 的 MySQL/MariaDB 數據庫管理和開發工具。它提供了一個直觀的圖形用戶界面&#xff0c;使得我們無需精通復雜的 SQL 命令也能執行大多數數據庫管理任務。 phpMyAdmin 項目曾經暫停將近兩年&#xff0c;不過 2025 年又開始發布新版本了。 …

存儲服務一NFS文件存儲概述

前言&#xff1a; 網絡文件系統&#xff08;Network File System&#xff0c;NFS&#xff09;誕生于1984年&#xff0c;由Sun Microsystems首創&#xff0c;旨在解決異構系統間的文件共享需求。作為一種基于客戶端-服務器架構的分布式文件協議&#xff0c;NFS允許遠程主機通過T…

libimagequant 在 mac 平臺編譯雙架構

在 macOS 上編譯 libimagequant 的雙架構&#xff08;aarch64 x86_64&#xff09;通用二進制庫&#xff0c;以下是完整步驟&#xff1a;??1. 準備 Rust 工具鏈?? # 安裝兩個目標平臺 rustup target add aarch64-apple-darwin x86_64-apple-darwin# 確認安裝成功 rustup ta…

暑期自學嵌入式——Day01(C語言階段)

點關注不迷路喲。你的點贊、收藏&#xff0c;一鍵三連&#xff0c;是我持續更新的動力喲&#xff01;&#xff01;&#xff01; 主頁&#xff1a; 一位搞嵌入式的 genius-CSDN博客https://blog.csdn.net/m0_73589512?spm1011.2682.3001.5343感悟&#xff1a; 今天我認為最重…

Flutter基礎(前端教程⑧-數據模型)

這個示例展示了如何創建數據模型、解析 JSON 數據&#xff0c;以及在 UI 中使用這些數據&#xff1a;import package:flutter/material.dart; import dart:convert;void main() {// 示例&#xff1a;手動創建User對象final user User(id: 1,name: 張三,age: 25,email: zhangsa…

SSRF10 各種限制繞過之30x跳轉繞過協議限制

ssrf漏洞在廠商的處理下可能進行一些特殊處理導致我們無法直接利用漏洞 有以下四種&#xff1a; 1.ip地址限制繞過 2.域名限制繞過 3.30x跳轉繞過域名限制 4.DNS rebinding繞過內網ip限制 本章我們講30x跳轉繞過域名限制 30x跳轉繞過域名限制 之前我們使用ssrf漏洞時可以…

DNS解析過程和nmap端口掃描

目錄 DNS解析流程&#xff1a; nmap端口掃描 指定掃描方式 TCP全連接掃描 -sT SYN半連接掃描 -sS -sT和 -sS的區別 Linux提權 利用好谷歌語法查找敏感信息 如果自己搭建了網站文件要放在phpstudy_pro\WWW下。 如果想要使用域名訪問網站&#xff0c;需要在phpstudy_pro…

【基于開源大模型(如deepseek)開發應用及其發展趨勢的一點思考】

1. 開源大模型技術發展現狀1.1 DeepSeek等主流開源大模型的技術特性分析 DeepSeek作為當前最具代表性的開源大模型之一&#xff0c;其技術架構具有多項創新特性。該模型采用混合專家架構(MoE)&#xff0c;通過將視覺編碼分離為"理解"和"生成"兩條路徑&…

java8 ConcurrentHashMap 桶級別鎖實現機制

Java 8 ConcurrentHashMap 桶級別鎖實現機制 Java 8 中的 ConcurrentHashMap 拋棄了分段鎖設計&#xff0c;采用了更細粒度的桶級別鎖&#xff08;bucket-level locking&#xff09;實現&#xff0c;這是其并發性能提升的關鍵。下面詳細解析其實現原理&#xff1a; 1. 基本實現…

Python正則表達式實戰指南

一 正則表達式庫正則表達式是文本處理中不可或缺的強大工具&#xff0c;Python通過re模塊提供了完整的正則表達式支持。本文將詳細介紹re模塊中最常用的match()、search()和findall()函數&#xff0c;以及貪婪模式與非貪婪模式的區別&#xff0c;幫助讀者掌握Python中正則表達式…

使用球體模型模擬相機成像:地面與天空的可見性判斷與紋理映射

在傳統相機模擬中&#xff0c;地面通常被建模為一個平面&#xff08;Plane&#xff09;&#xff0c;這在低空場景下是合理的。但在更大視場范圍或遠距觀察時&#xff0c;地球的曲率不可忽視。因此&#xff0c;我們需要將地面模型從平面升級為球體&#xff0c;并基于球面與光線的…

Agent自動化與代碼智能

核心問題&#xff1a; 現在很多團隊做AI系統有個大毛病&#xff1a;只顧追求“高大上”的新技術&#xff08;尤其是AI Agent&#xff09;&#xff0c;不管實際業務需不需要。 結果系統搞得又貴、又復雜、還容易出錯。大家被“Agent”這個概念搞暈了&#xff1a;到底啥時候用簡單…

SQL141 試卷完成數同比2020年的增長率及排名變化

SQL141 試卷完成數同比2020年的增長率及排名變化 withtemp as (selectexam_id,tag,date(submit_time) as submit_timefromexamination_infoleft join exam_record using (exam_id)wheresubmit_time is not null),2021_temp as (selecttag,count(*) as exam_cnt_21,rank() over…

C語言<數據結構-單鏈表>

鏈表是一種常見且重要的數據結構&#xff0c;在 C 語言中&#xff0c;它通過指針將一系列的節點連接起來&#xff0c;每個節點可以存儲不同類型的數據。相比數組&#xff0c;鏈表在插入和刪除元素時不需要移動大量數據&#xff0c;具有更好的靈活性&#xff0c;尤其適合處理動態…

archive/tar: unknown file mode ?rwxr-xr-x

這個是我在docker build報錯的&#xff0c;這是一個node.js項目。我猜你也是一個node.js下的項目&#xff0c;或者前端項目。 解決方法&#xff1a; .dockerignore里面寫一下node_modules就行了。 未能解決&#xff1a;archive/tar&#xff1a;未知文件模式&#xff1f;rwxr-…

【前端】ikun-markdown: 純js實現markdown到富文本html的轉換庫

文章目錄背景界面當前支持的 Markdown 語法不支持的Markdown 語法代碼節選背景 出于興趣,我使用js實現了一個 markdown語法 -> ast語法樹 -> html富文本的庫, 其速度應當慢于正則實現的同類js庫, 但是語法擴展性更好, 嵌套列表處理起來更方便. 界面 基于此js實現vue組…

【echarts踩坑記錄】為什么第二個Y軸最大值不整潔

目錄問題復現示意圖&#xff1a;解決方法有以下幾種&#xff1a;1. 在y軸配置中手動設置max屬性&#xff1a;2. 使用ECharts提供的坐標軸標簽格式化功能&#xff1a;&#x1f680;寫在最后問題復現示意圖&#xff1a; 今天在用echarts圖表的時候&#xff0c;出現了一個小問題。…