문제링크 : https://leetcode.com/problems/trapping-rain-water/
비슷하지만 비교적 쉬운 백준 링크 : https://www.acmicpc.net/problem/14719
문제
빗물이 고이는 원리
빗물이 고이려면 현재위치의 높이를 기준으로
왼쪽과 오른쪽이 ‘현재 높이보다 높아야’ 한다
이때, 쌓이는 양은 min(왼쪽, 오른쪽) - 현재 위치의 높이
가 된다
height 전체를 확인하지않고, 결과를 확인할수 있는 방법이 있을까?
결론은 안될것같다.
빗물의 양을 구하는 곳에서는 총 3곳의 블록값을 보는데 ‘내 위치, 왼쪽, 오른쪽' 이 되는데
주어지는 height
블록의 리스트 값이 모두 다르기 때문에
각 좌표의 블록값에 맞추어서 찾는것이 맞는것같다
백준에선 뚫리고, 리트코드에선 안뚫리는 소스코드
height = [0,1,0,2,1,0,1,3,2,1,2,1]
W = len(height)
answer = 0
for i in range(1, W-1):
left_block = max(height[ :i]) #내 왼쪽에서 제일 높은벽
right_block = max(height[i+1: ]) #내 오른쪽에서 제일 높은벽
minimum = min(left_block, right_block) #어차피 높이는 둘중 낮은값만큼 쌓임
if minimum > height[i]: #나보다 높은벽들 사이에 있다면
answer += minimum - height[i]
print( answer )
현재 위치를 기준으로, 왼쪽에서 가장 높은벽, 오른쪽에서 가장 높은벽을 확인한다. 둘중 낮은값을 확인하고
내가 둘중 낮은값보다 낮은위치라면, 물을 쌓이는 방식이다
이 소스코드가 리트코드에서는 안뚫리는 이유는 left_block, right_block
을 구하는 과정 때문이다max()
를 쓰는데, 이때 인덱스 i
를 기준으로 ‘좌측의 모든 배열값' 과 ‘우측의 모든 배열값' 을 구하기 때문이고
구간을 절반씩 나누므로 O( n**2 / n)
이 되어서 결국 시간복잡도에서 터질것이다
리트코드에서도 뚫리는 소스코드
class Solution:
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
areas = 0
max_l = max_r = 0
l = 0
r = len(height)-1
while l < r:
if height[l] < height[r]:
if height[l] > max_l:
max_l = height[l]
else:
areas += max_l - height[l]
l +=1
else:
if height[r] > max_r:
max_r = height[r]
else:
areas += max_r - height[r]
r -=1
return areas
투포인터를 써서 푸는 방식이다
좌, 우 에 포인터를 하나씩 두고, 각 위치의 높이값을 확인한다
왼쪽, 혹은 오른쪽을 기준으로 시작해서
왼쪽의 바로 왼쪽값, 오른쪽의 오른쪽 값을 확인하되
가장 높았던 왼쪽값, 가장 높았던 오른쪽 값을 가지고 있는다
이렇게하면 좋은점은 height[ : l]
혹은 height[r: ]
로 가장 높았던 값을 확인할 필요가 없어진다는거다.
리스트 인덱싱에 O(n)
만큼 들어갈거고, 매 iteration만큼 돌테니까 길이가 L
이라면 O(n *L)
을 줄일수 있는것이다
'CodingTest' 카테고리의 다른 글
백준 18232 텔레포트정거장 파이썬 (0) | 2022.07.20 |
---|---|
백준 10826 피보나치수4 파이썬 (0) | 2022.07.20 |
백준 2606 바이러스 (0) | 2022.07.13 |
백준 14888 연산자끼워넣기 파이썬 (0) | 2022.07.08 |
백준 11725 트리의 부모 찾기 파이썬 (0) | 2022.07.05 |