LeetCode——42. 接雨水(Java)
阿新 • • 發佈:2021-11-03
題目描述
題幹:
給定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
題目描述
返回能接到的雨水格子數,官方題解給出了很多種方法,說幾個可以理解的方法 任何問題離不開暴力解答,但是這道題的暴力思想我估計都不好想 你需要知道如何計算節水數量的方式,就是當前元素到左右最高邊界中較小的差然後求和 所以我們需要先計算出每個元素盛水的左右邊界值,這裡就有兩種方式 暴力的話就需要每次計算左右邊界,如果採用動態規劃的思想,可以想把邊界值儲存起來 這就是兩種方法,再其次就是採用單調遞減棧的方式,因為只要高度是遞減的 那當它一旦遇到遞增的就可以接水,利用這個思路,我們可以使用遞減棧的思想來計算 最後還有一種雙指標的方式,因為時間有限就沒有理解,大家可以去官方題解檢視解析或者視訊
正確程式碼
// 暴力 public int trap(int[] height) { int ans = 0; int size = height.length; for (int i = 1; i < size - 1; i++) { int max_left = 0, max_right = 0; for (int j = i; j >= 0; j--) { max_left = Math.max(max_left, height[j]); } for (int j = i; j < size; j++) { max_right = Math.max(max_right, height[j]); } ans += Math.min(max_left, max_right) - height[i]; } return ans; } // 動態規劃 public int trap01(int[] height) { if (height == null || height.length == 0) { return 0; } int ans = 0, size = height.length; int[] left_max = new int[size]; int[] right_max = new int[size]; left_max[0] = height[0]; for (int i = 1; i < size; i++) { left_max[i] = Math.max(height[i], left_max[i - 1]); } right_max[size - 1] = height[size - 1]; for (int i = size - 2; i >= 0; i--) { right_max[i] = Math.max(height[i], right_max[i + 1]); } for (int i = 1; i < size - 1; i++) { ans += Math.min(left_max[i], right_max[i]) - height[i]; } return ans; } // 單調遞減棧 public int trap02(int[] height) { int ans = 0, current = 0; Deque<Integer> stack = new LinkedList<>(); while (current < height.length) { while (!stack.isEmpty() && height[current] > height[stack.peek()]) { int top = stack.pop(); if (stack.isEmpty()) break; int distance = current - stack.peek() - 1; int bounded_height = Math.min(height[current], height[stack.peek()]) - height[top]; ans += distance * bounded_height; } stack.push(current++); } return ans; } // 雙指標 public int trap03(int[] height) { int left = 0, right = height.length - 1; int ans = 0; int left_max = 0, right_max = 0; while (left < right) { if (height[left] < height[right]) { if (height[left] >= left_max) { left_max = height[left]; } else { ans += (left_max - height[left]); } ++left; } else { if (height[right] >= right_max) { right_max = height[right]; } else { ans += (right_max - height[right]); } --right; } } return ans; }
總結
上次說到單調遞減棧可以用來統計元素後面比自己大的元素,在這裡也同樣好用
還有雙指標的思想,絕對是將複雜度降低的絕妙方式,我個人就很喜歡這個思想
如果文章存在問題或者有更好的題解,歡迎在評論區斧正和評論,各自努力,最高處見