# Problem
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining. Example 2:
|
# My Answer = Solution1
class Solution:
def trap(self, height: List[int]) -> int:
h = 0
t = len(height)-1
hmax = 0
tmax = 0
answer = 0
while h < t:
if height[h]<= height[t]:
if height[h]>hmax:
hmax = height[h]
answer += hmax-height[h]
h += 1
else:
if height[t]>tmax:
tmax = height[t]
answer += tmax-height[t]
t -= 1
return answer
# Solution 1 - 투 포인터를 최대로 이동
class Solution:
def trap(self, height: List[int]) -> int:
if not height:
return 0
volume = 0
left, right = 0, len(height) - 1
left_max, right_max = height[left], height[right]
while left < right:
# 최대값 업데이트
left_max, right_max = max(height[left], left_max), max(height[right], right_max)
# 더 높은 쪽을 향해 투 포인터 이동
if left_max <= right_max:
volume += left_max - height[left]
left += 1
else:
volume += right_max - height[right]
right -= 1
return volume
높이가 최대인 지점에서 left, right 가 만나게 됨
# Solution 2 - 스택 쌓기
class Solution:
def trap(self, height: List[int]) -> int:
stack = []
volume = 0
for i in range(len(height)):
# 변곡점을 만나는 경우
while stack and height[i] > height[stack[-1]]: # 이 부분 반복!!!!!
# 스택에서 꺼낸다
top = stack.pop()
if not len(stack): # 스택이 비면 -> 길이가 0
break
# 이전과의 차이만큼 물 높이 처리
distance = i - stack[-1] - 1 # 인덱스는 0 부터 시작하므로 1을 더 빼줌
waters = min(height[i], height[stack[-1]]) - height[top]
volume += distance * waters
stack.append(i)
return volume
스택에 쌓아 나가면서 현재 높이가 이전 높이보다 높을 때 격차만큼 물 높이를 채운다
i | stack | height[i] | height[stack[-1]] | top | distannce | waters | volume |
[] | 0 | ||||||
0 | [0] | 0 | 0 | ||||
1 | [] | 1 | 0 | ||||
[1] | 1 | ||||||
2 | [1,2] | 0 | 0 | ||||
3 | [1] | 2 | 1 | 2 | 3-1-1 = 1 | min(2,1)-0 = 1 | +1 |
[] | 2 | 1 | |||||
[3] | 2 | ||||||
4 | [3,4] | 1 | 1 | ||||
5 | [3,4,5] | 0 | 0 | ||||
6 | [3,4] | 1 | 1 | 5 | 6-4-1 = 1 | min(1,1)-0 = 1 | +1 |
[3,4,6] | 1 | ||||||
7 | [3,4] | 3 | 1 | 6 | 7-4-1 = 2 | min(3,1)-1 = 0 | 0 |
[3] | 3 | 2 | 4 | 7-3-1 = 3 | min(3,2)-1 = 1 | +3 | |
[] | 3 | 3 | |||||
[7] | 3 | ||||||
8 | [7,8] | 2 | 2 | ||||
9 | [7,8,9] | 1 | 1 | ||||
10 | [7,8] | 2 | 2 | 9 | 10-8-1 = 1 | min(2,2)-1 = 1 | +1 |
[7,8,10] | 2 | ||||||
11 | [7,8,10,11] | 1 | = 6 |
i = 7 일 때 while 문이 반복된다. -> 층별로 계산
현재 height가 3일 때, 이전 블록이 3일때, 2일 때 , 1일 때
이전보다 높은 블럭일 때마다 계산 - > 지금 블럭과 사이에 빗물이 쌓일 수 있는 낮은 이전 블럭들을 스택에 넣음
water에서 낮은 벽까지만 빗물이 쌓일 수 있으므로 min(height[i],height[stack[-1]])
높은 벽 안에 낮은벽이 있어서 쌓일 수 있을 경우 맨 밑부터 계산 -> height[top]은 이미 계산되었으므로 빼준다.
ex) 2-1-0-3 의 경우
1 | 2 | 3 | 4 |
stack 에는 1,2가 들어있을 것임 (stack = [1,2]), top = 3
1) 먼저 2열과 4열 사이의 1칸 계산
2열과 4열 중 낮은 2열의 높이 1, 3열(top)의 높이는 0이므로 계산할 높이는 1
stack = [1], top = 2
2) 1열과 4열 사이의 2칸 계산 (이때 top은 2열의 높이 = 1)
이때 물이 채워질 수 있는 높이는 1열과 4열 중 낮은 1열 = 2
2열과 같이 1열과 4열 사이에 더 낮은 높이의 블록이 있다면 1)에서 이미 계산되었으므로 전체 높이에서 그만큼의 높이 빼주기
----> 2*(2-1) = 1
ex) 3-1-0-1의 경우
stack 에는 1,2가 들어있을 것임 (stack = [1,2]), top = 3
1) 먼저 2열과 4열 사이의 1칸 계산
2열과 4열 중 낮은 2열의 높이 1, 3열(top)의 높이는 0이므로 계산할 높이는 1-0 = 1
stack = [1], top = 2
2) 1열과 4열 사이의 2칸 계산
1열과 4열의 높이가 같으므로 이때 물이 채워질 수 있는 높이 = 3
2열과 같이 1열과 4열 사이에 더 낮은 높이의 블록이 있다면 이미 계산되었으므로 그만큼의 높이를 빼주어야 한다. (3-1 = 2)
----> 2*(3-1) = 4
'Algorithm > LEET CODE ( 파이썬 알고리즘 인터뷰)' 카테고리의 다른 글
[LEET CODE] 561. Array Partition I (0) | 2021.03.21 |
---|---|
[LEET CODE] 15. 3Sum ( 투 포인터 활용) (0) | 2021.03.21 |
[LEET CODE] 1. Two Sum (0) | 2021.03.19 |
[LEET CODE] 5. Longest Palindromic Substring (0) | 2021.03.16 |
[LEET CODE] 49. Group Anagrams (dict 자료형, sort(), sorted()) (0) | 2021.03.15 |