- vừa được xem lúc

3 ways - Trapping Rain water

0 0 2

Người đăng: MinhDrake

Theo Viblo Asia

Problem Restatement or Summarize

Given an array height[0…n-1] ( length n ) of non-negative integers, each representing a bar of width 1. Compute the total units of water that can be trapped between the bars after it rains.

image.png

1. Brute-force baseline

For each index i, scan left to find the tallest bar to its left, scan right to find the tallest bar to its right, then calculate

water_at_i = max(0, min(max_left_at_i, max_right_at_i) - height[i])

pros: trivial to derive

cons: O(n2) in the worst case.

2. Precompute - arrays(DP-Style) - O(n) time, O(n) space

Core idea

Instead of rescanning on each i, we can reuse the result of the latest maximum in left (or right) we just calculate recently.

Implementation


# Build the array
maxLeft = [0]*n
for i in range(1, n): maxLeft[i] = max(maxLeft[i-1], height[i-1]) maxRight = [0]*n
for i in range(n-2, -1, -1): maxRight[i] = max(maxRight[i+1], height[i+1]) # at each step calculate
water_at_i = max(0, min(max_left_at_i, max_right_at_i) - height[i])

Pros: Debug easily, you can monitor at each step to see what the result is and compare with the example

Cons: we are using two extra arrays with the length of n , so its can be disaster.

3. Two-pointer technique - O(n) time, O(1) extra space

Core insight

At any position i, trapped water can calculate based on the smaller of two heighest length on left and right hands. The two pointers trick maintains two running maxima and gradually inward for both side. Focus on three points:

  • Pointers

    • l starts at 0, r at n−1.
  • Running maxima

    • leftMax = max height seen so far from the left up to l.
    • rightMax = max height seen so far from the right down to r.
  • Key decision at each step

    Compare height[l] vs. height[r]:

    • If height[l] ≤ height[r], then left side is the bottleneck (limiting wall) for index l.
    • Else, right side is the bottleneck for index r.

Why? When height[l] ≤ height[r], you are guaranteed that some bar to the right (namely at r) is at least as tall as height[l]. Therefore the limiting wall for l is leftMax, and you can safely compute


water_at_l = leftMax – height[l]

without ever needing the full right-side max array.

Pseudocode

java
Sao chépChỉnh sửa
int l = 0, r = n − 1;
int leftMax = 0, rightMax = 0;
int trapped = 0; while (l ≤ r) { if (height[l] ≤ height[r]) { // process l leftMax = max(leftMax, height[l]); trapped += leftMax − height[l]; l++; } else { // process r rightMax = max(rightMax, height[r]); trapped += rightMax − height[r]; r--; }
}
return trapped; 

Detailed Run

Let’s go through [0,3,0,2,0,4] (res = 7)

Step l r height[l] height[r] leftMax rightMax Action trapped
init 0 5 0 4 0 0 compare 0≤4 0
1 0 5 0 4 0→0 trapped+=0−0=0; l=1 0
2 1 5 3 4 0→3 trapped+=3−3=0; l=2 0
3 2 5 0 4 3 trapped+=3−0=3; l=3 3
4 3 5 2 4 3 trapped+=3−2=1; l=4 4
5 4 5 0 4 3 trapped+=3−0=3; l=5 7
6 5 5 4 4 3→4 trapped+=4−4=0; l=6 7

Why It’s Correct

  • Whenever you process the lower side pointer, you know the opposite side pointer guarantees a wall at least as tall for bounding water.
  • By updating leftMax only when height[l] ≤ height[r], you maintain the invariant leftMax ≤ rightMax. Thus min(leftMax, rightMax) = leftMax, and computing leftMax − height[l] is valid.

Pros: Use linear time with O(1) space - The optimized one Cons: you need to keep invariant through all the times

In Summary

  • Brute-force is simplest to derive but quadratic.
  • Precompute-arrays hits linear time with linear extra space—great for clarity.
  • Two-pointer achieves linear time and constant space by leveraging the fact that the lower of the two pointers at each step is the true limiting wall for water at that position.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Hướng dẫn finetune mô hình LLM đơn giản và miễn phí với Unsloth

Chào mừng các bạn đến với bài viết hướng dẫn chi tiết cách finetune (tinh chỉnh) một mô hình ngôn ngữ lớn (LLM) một cách đơn giản và hoàn toàn miễn phí sử dụng thư viện Unsloth. Trong bài viết này, ch

0 0 7

- vừa được xem lúc

SERIES INDEX NÂNG CAO - BÀI 1: PHÂN TÍCH NHỮNG SAI LẦM PHỔ BIẾN KHI SỬ DỤNG INDEX TRONG MYSQL

Nếu anh em thấy hay thì ủng hộ tôi 1 follow + 1 upvote + 1 bookmark + 1 comment cho bài viết này tại Mayfest 2025 nhé. Còn nếu bài viết chưa hữu ích thì tôi cũng hi vọng anh em để lại những góp ý thẳn

0 0 8

- vừa được xem lúc

"Hack" Não Số Lớn Với Digit DP!

Xin chào anh em, những chiến binh thuật toán kiên cường. Phản ứng đầu tiên của nhiều anh em (có cả tôi): "Ối dào, dễ! Quất cái for từ 1 đến 101810^{18}1018 rồi check thôi!".

0 0 10

- vừa được xem lúc

So Sánh StatelessWidget và StatefulWidget & Các Widget Nâng Cao

Chào mọi người! Hôm nay chúng ta sẽ tiếp tục hành trình khám phá Flutter và đến với bài học về StatelessWidget và StatefulWidget. Trong bài này, mình sẽ giúp các bạn phân biệt sự khác nhau giữa hai lo

0 0 7

- vừa được xem lúc

React Lifecycle & Hooks Cơ Bản

React cung cấp các phương thức lifecycle và hooks để quản lý các giai đoạn khác nhau trong vòng đời của component. Việc hiểu rõ các phương thức này giúp bạn có thể tối ưu hóa ứng dụng React của mình.

0 0 7

- vừa được xem lúc

Kafka Fundamental - Bài 4: Consumers, Deserialization, Consumer Groups & Consumer Offsets

Xin chào, lại là mình - Đức Phúc, anh chàng hơn 6 năm trong nghề vẫn nghèo technical nhưng thích viết Blog để chia sẻ kiến thức bản thân học được trong quá trình “cơm áo gạo tiền” đây. Các bạn có thể

0 0 5