Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬으로 빗물 가두기(Trapping Rain Water) 문제 해결하기

빗물 가두기(Trapping Rain Water) 문제란?

n개의 음수가 아닌 정수로 이루어진 배열이 있다고 가정해 봅시다. 이 배열은 각 막대의 너비가 1인 고도 지도(elevation map)를 나타내며, 비가 내린 후 이 지형에 얼마나 많은 물을 가둘 수 있는지 계산하는 것이 목표입니다. 예를 들어 다음과 같은 지형이 있다고 할 때 −

파이썬으로 빗물 가두기(Trapping Rain Water) 문제 해결하기

위 그림에서 파란색으로 표시된 물웅덩이가 총 6칸이므로, 결과값은 6이 됩니다.

이 문제는 각 위치에서 왼쪽과 오른쪽 경계 중 더 낮은 높이만큼 물이 차오른다는 원리를 이용하며, 스택(stack) 자료구조를 활용하면 한 번의 순회로 효율적으로 해결할 수 있습니다.

알고리즘 단계

  • 스택 st와 water := 0, i := 0으로 초기화합니다.

  • i가 height 배열의 길이보다 작은 동안 아래 과정을 반복합니다.

    • 스택이 비어 있거나 height[스택 최상단 값] >= height[i]라면, 현재 인덱스 i를 스택에 push하고 i를 1 증가시킵니다.

    • 그렇지 않다면(현재 높이가 스택 top보다 높아 웅덩이가 생길 수 있는 경우):

      • x := 스택 top 요소를 꺼내고(pop) 저장합니다.

      • 스택이 비어 있지 않다면:

        • temp := min(height[스택 top], height[i]) — 좌우 경계 중 낮은 값

        • dist := i – 스택 top – 1 — 두 경계 사이의 거리

        • water := water + dist × (temp – height[x]) — 해당 구간에 채워지는 물의 양을 누적

  • 반복이 끝나면 누적된 water 값을 반환합니다.

예시 코드

다음 파이썬 구현을 통해 더 쉽게 이해할 수 있습니다 −

class Solution(object):
   def trap(self, height):
      stack = []
      water = 0
      i = 0
      while i < len(height):
         if len(stack) == 0 or height[stack[-1]] >= height[i]:
            stack.append(i)
            i += 1
         else:
            x = stack[-1]
            stack.pop()
            if len(stack) != 0:
               temp = min(height[stack[-1]], height[i])
               dist = i - stack[-1] - 1
               water += dist * (temp - height[x])
      return water
ob = Solution()
print(ob.trap([0,1,0,2,1,0,1,3,2,1,2,1]))

입력

[0,1,0,2,1,0,1,3,2,1,2,1]

출력

6

시간 및 공간 복잡도

각 인덱스는 스택에 최대 한 번 push되고 한 번 pop되므로 시간 복잡도는 O(n)입니다. 스택에는 인덱스가 저장되므로 공간 복잡도 역시 최악의 경우 O(n)입니다.