오늘 코딩테스트를 보다가 오랜만에 '별 찍기' 문제를 보게 됐다.
해당 문제에서 좀 까다로웠던 부분만 하위 문제로 새롭게 만들어봤다.
Q. 여러 좌표가 주어질 때 이쁘게 별(*) 찍기
(-1, 0), (1, 0) 과 같은 좌표가 주어지면,
주어진 좌표는 '*'로 표시하고, 나머지는 '.'로 표시한다.
즉, ['*.*'] 로 출력한다.
물론 board의 크기 제한은 없지만,
['...', '*.*']로 출력하면 안 된다. 즉, '...'는 굳이 필요 없으므로 제거한다.
별로 어렵지 않은 문제인데, 구현을 어떻게 하면 간단히 할까라는 생각을 시험 끝나고 생각해보다가,
다음과 같이 함수화시켜봤다.
points_to_star 함수는 점들이 주어지면 해당 점들에 대해 '*'로 board에 표시해주는 함수다.
from random import randint
def points_to_star(points):
"""
This function is to mark points(x, y) to star(*) in the board.
Input: [(x1, y1), (x2, y2), .... ] 좌표들의 집합
Output: 좌표는 (*)로 출력하고 아닐 경우 (.)로 출력
단, board 크기는 (*)의 최소, 최대에 따라 이쁘게 출력. (e.g. ["...", "*.."] (<-wrong), ["*.."] (<-correct)
Examples:
>>> points_to_star([(-1, 0), (1, 0)])
['*.*']
>>> points_to_star([(0, 0)])
['*']
>>> points_to_star([(-2, 3), (5, 4)])
['.......*', '*.......']
"""
min_x = min(points, key=lambda x: x[0])[0]
max_x = max(points, key=lambda x: x[0])[0]
min_y = min(points, key=lambda x: x[1])[1]
max_y = max(points, key=lambda x: x[1])[1]
board = [["."] * (max_x - min_x + 1) for _ in range(min_y, max_y+1)]
# parallel translation (min_x, max_y) -> (0, 0)
# y means row, x means col
for x, y in points:
board[abs(y-max_y)][x-min_x] = "*"
ans = ["".join(i) for i in board]
return ans
if __name__ == "__main__":
import doctest
doctest.testmod()
n = 5
points = []
for i in range(n):
x = randint(-10, 10)
y = randint(-10, 10)
points.append([x, y])
print(f'Question\n {points}')
print(f'GOT\n {points_to_star(points)}')
풀이방법
1) min_x, max_x, min_y, max_y 구하기
'*'를 모두 나타내는데 필요한 최소 board 크기를 구한다. 즉, points 집합에서 min_x, max_x, min_y, max_y를 구한다.
2) 최소한의 크기의 board 만들기
(max_y-min_y+1, max_x-min_x+1) 모양의 board를 만든다. 그리고 '.'로 초기화한다.
여기서 주의할 건, 좌표상 y는 board에서는 row이고, 좌표상 x는 board에서 col로 매칭된다.
예시)
(min_x, max_y) | (max_x, max_y) | ||
(min_x, min_y) | (max_x, min_y) |
표에 색칠이 안 돼서 위와 같이 표시했다.
위 그림을 보면 (x, y) 좌표는 list에서 각각 (col, row)랑 연관있다는 걸 알 수 있다.
3) points 집합에 있는 좌표는 '*'로 바꾸기
이때, (min_x, max_y)를 (0, 0)으로 평행이동시켰다. 물론 이 부분은 for문 2개 돌리며 구현해도 되지만, 평행이동시키면 코드가 한 줄로 깔끔해져서 이렇게 풀었다.
평행이동으로 구현할 때 주의할 점은, 원래 (x, y) 좌표가 board에서는 (abs(y - max_y), x - min_x)로 표현된다. 음수가 나올 수도 있어서 해당 부분을 절댓값 처리해야 한다.
그리고 마지막은 join을 이용해서 문자열로 연결했다. 참고로, 처음부터 각 행을 하나의 문자열로 만들지 않은 이유는 '*'자리는 '*'로 바꾸기 위함이었다.
좌표가 주어질 때 이쁘게 * 찍는 문제가 얼마나 등장할지 모르겠지만,
나중에 귀차니즘을 줄이기 위해 해당 부분을 함수로 만들어둔다.
'Problem Solving' 카테고리의 다른 글
2020년~2016년 주요 기업 코딩 테스트 유형 분석 (0) | 2021.01.16 |
---|