Pseudo code
1. 각 인덱스마다 높이를 담는 Stack 생성, 물이 찬 용량 변수 생성
2. 전체 배열 크기만큼 Loop
2-1. 변곡점을 만나면
2-1-1. 스택에서 꺼낸다 (Pop)
2-1-2. 만약 Stack이 비어있으면, 한쪽이 없는 버킷형태 (즉,상향선 혹은 하향선이 하나만 있는 모양이다.) -> 루프 탈출
2-1-3. 이전과의 차이만큼 물 높이 처리하고 물 찬 용량에 더한다.
2-2. 변곡점이 아니면 Stack에 인덱스값을 쌓는다.
3. 물이 찬 용량 return
Code
package main
import (
"fmt"
"math"
)
type Stack struct {
nums []int
count int
}
func NewStack() *Stack {
return &Stack{}
}
func (s *Stack) Push(n int) {
s.nums = append(s.nums, n) // 맨 위에 추가
s.count++
}
// 스택이 Pop되는 과정은 다음과 같다.
// [1 2 3]
// 3
// [1 2]
// 2
// [1]
// 1
// []
// 0
func (s *Stack) Pop() int {
if s.count == 0 {
return 0
}
s.count--
result := s.nums[s.count] // 슬라이스 재배열전에 return값 저장해두고
if s.count != 0 { // 슬라이스 요소의 갯수가 0이 아닐때
s.nums = append(s.nums[:s.count], []int{}...) // 슬라이스 마지막 요소 삭제
} else { // 요소의 갯수가 0일때
s.nums = nil // 슬라이스 할당 해제
s.nums = []int{} // 빈 슬라이스로 재할당
}
return result
}
func trap(height []int) int {
stack := NewStack()
volume := 0
for i := 0; i < len(height); i++ {
// 변곡점일 경우
for stack.count != 0 && height[i] > height[stack.nums[stack.count-1]] {
top := stack.Pop()
// 한쪽이 뚫린 양동이 (즉, 한쪽 상향선만 존재)
if stack.count == 0 {
break
}
distance := i - stack.nums[stack.count-1] - 1 // distance는 빗물이 담기는 버킷 가로의 길이
// math.Min은 float64 타입만 비교가능해서 type conversion
waters := math.Min(float64(height[i]), float64(height[stack.nums[stack.count-1]])) - float64(height[top]) // waters는 물이 차는 버킷의 세로 길이
volume += distance * int(waters)
}
// 변곡점이 아닐경우
stack.Push(i)
}
return volume
}
func main() {
// height := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1} // 6
height := []int{4, 2, 0, 3, 2, 5} // 9
result := trap(height)
fmt.Println(result)
}