Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

문제

샘의 집은 양 옆으로 사과나무와 오렌지 나무가 있어서, 과일이 풍부하다. 아래 그림에서 빨간색 영역은 집을 기리킨다. 집의 영역은 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[0] = point
}
func (h *Home) SetOrangePoint(point int) {
    h.Orange[0] = point
}

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

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

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

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][0]
    for _, point := range points {
        switch {
        case p < h.X0:
            if (p+point) >= h.X0 && (p+point) <= h.X1 {
                h.FruitTree[name][1]++
            }
        case p > h.X1:
            if (p+point) >= h.X0 && (p+point) <= h.X1 {
                h.FruitTree[name][1]++
            }
        }
    }
}

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

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)