日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

力扣- -接雨水

發布時間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 力扣- -接雨水 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

力扣- -接雨水

文章目錄

    • 力扣- -接雨水
    • 一、題目描述
    • 二、分析
    • 二、備忘錄優化
    • 三、雙指針解法

一、題目描述

二、分析

我第一次看到這個問題,無計可施,完全沒有思路,相信很多朋友跟我一樣。所以對于這種問題,我們不要想整體,而應該去想局部;就像之前處理字符串問題,不要考慮如何處理整個字符串,而是去思考應該如何處理每一個字符。

這么一想,可以發現這道題的思路其實很簡單。具體來說,僅僅對于位置 i,能裝下多少水呢?

  • 能裝 2 格水。為什么恰好是兩格水呢?因為 height[i] 的高度為 0,而這里最多能盛 2 格水,2-0=2。
  • 為什么位置 i 最多能盛 2 格水呢?因為,位置 i 能達到的水柱高度和其左邊的最高柱子、右邊的最高柱子有關,我們分別稱這兩個柱子高度為l_max和r_max;位置 i 最大的水柱高度就是min(l_max, r_max)。

更進一步,對于位置 i,能夠裝的水為:

water[i] = min(# 左邊最高的柱子max(height[0..i]), # 右邊最高的柱子max(height[i..end]) ) - height[i]



這就是本問題的核心思路,我們可以簡單寫一個暴力算法:

int trap(vector<int>& height) {int n = height.size();int ans = 0;for (int i = 1; i < n - 1; i++) {int l_max = 0, r_max = 0;// 找右邊最高的柱子for (int j = i; j < n; j++)r_max = max(r_max, height[j]);// 找左邊最高的柱子for (int j = i; j >= 0; j--)l_max = max(l_max, height[j]);// 如果自己就是最高的話,// l_max == r_max == height[i]ans += min(l_max, r_max) - height[i];}return ans; }

有之前的思路,這個解法應該是很直接粗暴的,時間復雜度 O(N^2),空間復雜度 O(1)。但是很明顯這種計算 r_max 和 l_max 的方式非常笨拙,一般的優化方法就是備忘錄。

二、備忘錄優化

  • 之前的暴力解法,不是在每個位置 i 都要計算 r_max 和 l_max嗎?我們直接把結果都緩存下來,別傻不拉幾的每次都遍歷,這時間復雜度不就降下來了嘛。
  • 我們開兩個數組 r_max 和 l_max 充當備忘錄,l_max[i] 表示位置 i 左邊最高的柱子高度,r_max[i] 表示位置 i 右邊最高的柱子高度。預先把這兩個數組計算好,避免重復計算:
int trap(vector<int>& height) {if (height.empty()) return 0;int n = height.size();int ans = 0;// 數組充當備忘錄vector<int> l_max(n), r_max(n);// 初始化 base casel_max[0] = height[0];r_max[n - 1] = height[n - 1];// 從左向右計算 l_maxfor (int i = 1; i < n; i++)l_max[i] = max(height[i], l_max[i - 1]);// 從右向左計算 r_maxfor (int i = n - 2; i >= 0; i--) r_max[i] = max(height[i], r_max[i + 1]);// 計算答案for (int i = 1; i < n - 1; i++) ans += min(l_max[i], r_max[i]) - height[i];return ans; }

這個優化其實和暴力解法差不多,就是避免了重復計算,把時間復雜度降低為O(N),已經是最優了,但是空間復雜度是 O(N)。下面來看一個精妙一些的解法,能夠把空間復雜度降低到 O(1)。

三、雙指針解法

這種解法的思路是完全相同的,但在實現手法上非常巧妙,我們這次也不要用備忘錄提前計算了,而是用雙指針邊走邊算,節省下空間復雜度。
首先,看一部分代碼:

int trap(vector<int>& height) {int n = height.size();int left = 0, right = n - 1;int l_max = height[0];int r_max = height[n - 1];while (left <= right) {l_max = max(l_max, height[left]);r_max = max(r_max, height[right]);left++; right--;} }
  • 對于這部分代碼,請問 l_max 和 r_max 分別表示什么意義呢?
  • 很容易理解,l_max 是 height[0..left] 中最高柱子的高度,r_max 是 height[right..end] 的最高柱子的高度。
  • 明白了這一點,直接看解法:
int trap(vector<int>& height) {if (height.empty()) return 0;int n = height.size();int left = 0, right = n - 1;int ans = 0;int l_max = height[0];int r_max = height[n - 1];while (left <= right) {l_max = max(l_max, height[left]);r_max = max(r_max, height[right]);// ans += min(l_max, r_max) - height[i]if (l_max < r_max) {ans += l_max - height[left];left++; } else {ans += r_max - height[right];right--;}}return ans; }

你看,其中的核心思想和之前一模一樣,換湯不換藥。但是細心的可能會發現次解法還是有點細節差異:
之前的備忘錄解法,l_max[i] 和 r_max[i] 代表的是 height[0..i] 和 height[i..end] 的最高柱子高度。

ans += min(l_max[i], r_max[i]) - height[i];


但是雙指針解法中,l_max 和 r_max 代表的是 height[0..left] 和 height[right..end] 的最高柱子高度。比如這段代碼:

if (l_max < r_max) {ans += l_max - height[left];left++; }

  • 此時的 l_max 是 left 指針左邊的最高柱子,但是 r_max 并不一定是 left指針右邊最高的柱子,這真的可以得到正確答案嗎?
  • 其實這個問題要這么思考,我們只在乎 min(l_max, r_max)。對于上圖的情況,我們已經知道 l_max < r_max 了,至于這個 r_max 是不是右邊最大的,不重要,重要的是 height[i] 能夠裝的水只和 l_max 有關。

總結

以上是生活随笔為你收集整理的力扣- -接雨水的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。