CLOSE

Recommanded Free YOUTUBE Lecture: <% selectedImage %>

### 문제

샘의 집은 양 옆으로 사과나무와 오렌지 나무가 있어서, 과일이 풍부하다. 아래 그림에서 빨간색 영역은 집을 기리킨다. 집의 영역은 s에서 부터 t 까지다. 사과나무는 집 왼쪽에 있고, 오렌지 나무는 오른쪽에 있다. 사과나무의 위치는 a 오랜제나무의 위치는 b라고 가정하자. 땅을 x축이라고 할 때, 과일이 땅에 떨어지면 x축의 위치에 값을 가질 것이다. 이때 과일이 떨어졌던 나무와의 거리 d를 계산 할 수 있을 것이다. 그림에서 사과의 경우 오른쪽방향으로 떨어졌으므로 양의 정수 값을 가진다.

땅에 떨어진 m개의 사과와 n개의 오렌지 가 있으며, 나무로 부터 떨어진 거리 d를 알고 있다면, 얼마나 많은 과일들이 샘의 집([s,t]) 에 떨어졌는지를 계산 할 수 있을 것이다. 샘의 집에 떨어진 사과와 오렌지의 갯수를 출력하라.

### 입력 형식

• 첫번째 줄에는 s 와 t의 값이 들어간다. 샘의 집이 차지하고 있는 위치가 되겠다.
• 두번째 줄은 a 와 b 로, 사과나무와 오렌지 나무의 위치다.
• 세번째 줄은 m 과 n 으로 사과와 오렌지의 갯수다.
• 네번째 줄은 m 개의 사과가 사과나무로 부터 떨어진 거리다.
• 다섯번째 줄은 n개의 오렌지가 오렌지나무로 부터 떨어진 거리다.

#### 출력 형식

두 개의 값을 출력한다.
1. 샘의 집에 떨어진 사과의 갯수
2. 샘의 집에 떨어진 오렌지의 갯수

### 입력 예제

7 11
5 15
3 2
-2 2 1
5 -6

### 출력 예제

1
1

### 설명

그림으로 그리면 쉽게 이해 할 수 있다. 이렇게 해서 사과 1, 오렌지 1이 출력된다.

### 구현

#### 간단 구현

package main

import (
"fmt"
)

type Home struct {
X0     int
X1     int
Apple  []int
Orange []int
}

func New(a1, a2 int) *Home {
h := Home{X0: a1, X1: a2}
if a1 > a2 {
h = Home{X0: a2, X1: a1}
}
h.Apple = make([]int, 2)
h.Orange = make([]int, 2)
return &h
}
func (h *Home) PrintArea() {
fmt.Println(h.X0, "~", h.X1)
}

func (h *Home) SetApplePoint(point int) {
h.Apple = point
}
func (h *Home) SetOrangePoint(point int) {
h.Orange = point
}

func (h *Home) AppleFallen(points []int) {
p := h.Apple
for _, point := range points {
switch {
case p < h.X0:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.Apple++
}
case p > h.X1:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.Apple++
}
}
}
}

func (h *Home) OrangeFallen(points []int) {
p := h.Orange
for _, point := range points {
switch {
case p < h.X0:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.Orange++
}
case p > h.X1:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.Orange++
}
}
}
}

func (h *Home) AppleCount() {
fmt.Println(h.Apple)
}
func (h *Home) OrangeCount() {
fmt.Println(h.Orange)
}

func main() {
myHome := New(5, 10)
myHome.SetApplePoint(2)
myHome.SetOrangePoint(16)
myHome.PrintArea()
myHome.AppleFallen([]int{2, 3, 5, 6, 9})
myHome.AppleCount()
myHome.OrangeFallen([]int{2, -7, -10})
myHome.OrangeCount()
}


돌아는 가는 코드다. 쓸데없는 중복이 있다. 중복을 모두 제거해서 깨끗하게 만들어보자.

#### 중복을 제거한 좀 더 나은 구현

package main

import (
"fmt"
)

type Home struct {
X0        int
X1        int
FruitTree map[string][]int
}

func New(a1, a2 int) *Home {
h := Home{X0: a1, X1: a2}
h.FruitTree = make(map[string][]int)
if a1 > a2 {
h = Home{X0: a2, X1: a1}
}
return &h
}
func (h *Home) PrintArea() {
fmt.Println(h.X0, "~", h.X1)
}

func (h *Home) SetFruitTree(name string, point int) {
h.FruitTree[name] = []int{point, 0}
}

func (h *Home) FruitFallen(name string, points []int) {
p := h.FruitTree[name]
for _, point := range points {
switch {
case p < h.X0:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.FruitTree[name]++
}
case p > h.X1:
if (p+point) >= h.X0 && (p+point) <= h.X1 {
h.FruitTree[name]++
}
}
}
}

func (h *Home) FruitCount(name string) {
fmt.Println(h.FruitTree[name])
}

func main() {
myHome := New(5, 10)
myHome.PrintArea()

myHome.SetFruitTree("apple", 2)
myHome.SetFruitTree("orange", 16)

myHome.FruitFallen("apple", []int{2, 3, 5, 6, 9})
myHome.FruitFallen("orange", []int{2, -7, -10})

myHome.FruitCount("apple")
myHome.FruitCount("orange")
}


쓸데없는 중복을 제거했다. 개선해보자.

#### 옵저버 패턴을 이용한 구현

집 영역을 관찰하다가 과일이 떨어지면 계수하는 서비스에 맞는 구조인 것 같다.

### 시행착오

해커랭크는 표준입력으로 코드를 테스트 한다. 실제 제출하는 코드는 bufio.NewScanner(os.Stdin)으로 표준입력을 받아서 공백문자로 Split 한후 문자열을 Int 형으로 변환하는 등의 과정이 필요하다.

처음에는 아래와 같이 코드를 만들었다. 이렇게 해서 돌렸더니, 약 70%의 테스트케이스에서 실패했다. 버퍼가 원인이었다. 아래와 같이 버퍼를 잡은 후 모든 테스트 케이스를 통과했다.
    scanner := bufio.NewScanner(os.Stdin)
buf := make([]byte, 0, 64*1024)
scanner.Buffer(buf, 1024*1024)
scanner.Split(bufio.ScanLines)