5~6week 구현

최효준·2022년 9월 5일
0

AlgorithmStudy

목록 보기
5/9

구현

1. 코딩테스트에서의 구현

코딩테스트에서 구현이란 '머릿속에 있는 알고리즘을 소스코드로 바꾸는 과정'을 말한다. 어떤 문제를 풀든 간에 소스 코드를 작성하는 과정은 필수이므로 구현 유형은 모든 범위의 코딩 테스트 문제 유형을 포함하는 개념이다.

흔히 문제 해결 분야에서 구현 유형의 문제는 '풀이를 떠올리는 것은 쉽지만 소스코드로 옮기기 어려운 문제'를 의미한다. 흔히 개발할 때 프로그래밍 언어의 문법에 능숙하고 코드 작성 속도가 빠른 사람들을 피지컬이 좋다고 얘기하는데 구현 유형의 문제는 그런 의미에서 '피지컬'을 요구하는 문제라고 할 수 있다.
알고리즘은 간단한데 코드가 지나칠 만큼 길어지는 문제, 특정 소수점 자리까지 출력해야 하는 문제, 문자열이 입력으로 주어졌을 때 한 문자 단위로 끊어서 리스트에 넣어야 하는(파싱) 문제 등이 까다로운 구현 유형의 문제로 둘 수 있는데 경험이 부족한 경우에는 이런 문제들을 만났을 때 당황할 수 있다. 때문에 구현 유형의 문제는 꾸준하게 실력을 늘려야 한다.
'이것이 취업을 위한 코딩 테스트다.' 책에서는 완전 탐색과 시뮬레이션 유형을 모두 '구현' 유형으로 묶어서 다룬다.
완전 탐색은 모든 경우의 수를 다 계산하는 해결방법을 의미한다.
시뮬레이션은 문제에서 제시한 알고리즘을 한 단계씩 차례대로 직접 수행해야 하는 문제 유형을 의미힌다.
보통 두 유형모두 구현의 핵심이 되는 경우가 많아서 한번에 묶어서 다룬다.

2. 구현 시 고려해야 할 메모리 제약 사항

  1. C/C++에서 변수의 표현 범위
    기본 int 자료형의 표현 범위는 -2147483648 ~ 2147483647이고 이보다 큰 수는 long long과 같은 자료형을 사용한다. 하지만 long long 또한 9223372036854775807보다 큰 수를 처리할 수 없어 이보다 큰 수를 처리할 때는 BigInteger클래스를 구현하거나 이용해야 한다. C/C++ 에서는 이를 직접 구현해서 사용해야 하기에 유의할 것.
    하지만 보통 코딩테스트에서는 long long에서 다룰 수 있는 정수보다 큰 수는 잘 출제하는 않는다.

  2. 파이썬에서 리스트 크기
    파이썬을 사용하는 사람들은 리스트를 이용할 시에 코딩 테스트에서의 메모리 제한을 유의해야한다. 보통 코딩테스트에서는 128 ~ 512MB로 메모리를 제한하는데 알고리즘 문제 중에서는 종종 수백만 개 이상의 데이터를 처리해야 하는 문제들이 출제되고는 한다. 파이썬은 다른 언어에 비해 구현상의 복잡함이 적은 편이지만 메모리를 많이 사용하기 때문에 데이터 처리량이 많을 경우 메모리 제한을 고려해야한다.

    int 자료형 데이터의 개수에 따른 메모리 사용량
    데이터의 개수 메모리 사용량
    1000 약 4KB
    1000000 약 4MB
    10000000 약 40 MB

    3. 채점환경

    실제 온라인 저지 서비스에서의 채점 환경의 시스템 제한은 출제 기관마다 문제마다 조금씩 다르다. 각 코딩테스트 환경에서는 채점 시스템의 시간 제한 및 메모리 제한 정보가 함께 적혀있다. 파이썬의 경우에는 동작 속도가 다른 언어에 비해 느리므로 다른 언어들의 2배의 수행 시간 제한을 두기도 한다.
    파이썬으로 테스트 진행 시 1초에 2000만번의 연산을 수행한다고 가정하면 수행 시간 관리에 용이하다.
    시간 제한이 1초이고, 데이터의 개수가 100만개인 문제가 주어진다면 일반적으로 시간복잡도가 O(NlogN)이내인 알고리즘을 사용하여야 한다. N = 1000000이면 NlogN = 20000000이기 때문이다.
    이처럼 문제의 시간 제한과 데이터의 개수를 파악하고 어느 정도의 시간복잡도의 알고리즘을 작성해야 하는지 예측할 수 있어야한다.

    4. 구현 문제 접근법

    보통 구현 유형의 문제는 사소한 입력 조건 등을 문제에서 명시해주며 문제의 길이가 꽤 긴 편이다. 하지만 고차원적인 사고력을 요구하는 문제는 나오지 않는 편이니 문법에 익숙하다면 지레 겁먹지 않아도 금방 풀 수 있을 것이다.

    예시문제 1 상하좌우
    여행가 A는 N x N 크기의 정사각형 공간위에 서있다. 이 공간은 1 x 1 크기의 정사각형으로 나누어져 있다. 가장 왼쪽 위 좌표는 (1,1)이고 가장 오른쪽 아래 좌표는(N,N)이다. 여행가 A는 상하좌우 방향으로 이동할 수 있으며, 시작 좌표는 항상 (1,1)이다. 여행가 A가 이동할 계획이 적힌 계획서가 놓여져 있는데 계획서에는 하나의 줄에 띄어쓰기를 기준으로 하여 L, R, U, D 중 하나의 문자가 반복적으로 적혀있다. 각 문자는 왼쪽으로 한 칸, 오른쪽으로 한 칸, 위로 한 칸, 아래로 한 칸 이동하는 것을 의미한다. 이때 여행가 A가 N x N 크기의 정사각형 공간을 벗어나는 움직임은 무시된다. 예를 들어 (1,1)위치에서 L 혹은 U를 만나면 무시된다.
    N=5 인 지도에서 R->R->R->U->D->D 인 계획서가 있을 때 여행가의 위치는 3,4가 된다. 공간의 크기와 계획서가 주어졌을 때 여행가 A의 최종위치를 구하는 프로그램을 작성하라.

    solution

# N을 입력받기
n = int(input())
x, y = 1, 1
plans = input().split()

# L, R, U, D에 따른 이동 방향
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
move_types = ['L', 'R', 'U', 'D']

# 이동 계획을 하나씩 확인
for plan in plans:
	# 이동 후 좌표 확인
    for i in range(len(move_types)):
    	if plan == move_type[i]:
        	nx = x + dx[i]
            ny = y + dy[i]
        # 공간을 벗어나는 경우 무시
        if nx < 1 or ny < 1 or nx > n or ny > n:
        	continue
        # 이동 수행
        x, y = nx, ny
        
print(x, y)

예시문제 2 시각
정수 N이 입력되면 00시 00분 00초부터 N시 59분 59초까지의 모든 시각 주에서 3이 하나라도 포함되는 모든 경우의 수를 구하는 프로그램을 작성하시오. 예를 들어 1을 입력했을 때 다음은 3이 하나라도 포함되어 있으므로 세어야 하는 시각이다.
00시 00분 03초
00시 13분 30초
반면에 다음은 3이 하나도 포함되어 있지 않으므로 세면 안되는 시각이다.
00시 02분 55초
01시 27분 45초
첫째 줄에 정수 N이 입력된다.
모든 시각 중에서 3이 하나라도 포함되는 모든 경우의 수를 출력한다.

solution

n = int(input())

count = 0
for i in range(n+1):
	for j in range(60):
    	for k in range(60):
        	if '3' in str(i) + str(j) + str(k):
            	count += 1
print(count)

실전문제 1 왕실의 나이트
행복 왕국의 왕실 정원은 체스판과 같은 8 X 8 좌표 평면이다. 왕실 정원의 특정한 한 칸에 나이트가 서 있다. 나이트는 매우 충성스러운 신하로서 매일 무술을 연마한다.
나이트는 말을 타고 있기 때문에 이동을 할 때에는 L자 형태로만 이동할 수 있으며 정원 밖으로는 나갈 수 없다. 나이트는 특정한 위치에서 다음과 같은 2가지 경우로 이동할 수 있다.
수평으로 두 간 이동한 뒤에 수직으로 한 칸 이동하기
수직으로 두 간 이동한 뒤에 수평으로 한 칸 이동하기
이처럼 8 X 8 좌표 평면상에서 나이트의 위치가 주어졌을 때 나이트가 이동할 수 있는 경우의 수를 출력하는 프로그램을 작성하시오. 이때 왕실의 정원에서 행 위치를 표현할 때는 1부터 8로 표현하며, 열 위치를 표현할 때는 a부터 h로 표현한다.
예를 들어 만약 나이트가 a1에 있을 때 이동할 수 있는 경우의 수는 다음과 같은 2가지이다. a1의 위치는 좌표 평면에서 구석의 위치에 해당하며 나이트는 정원의 밖으로는 나갈 수 없기 때문이다.
오른쪽으로는 두 칸 이동 후 아래로 한 칸 이동하기 (c2)
아래로 두 칸 이동 후 오른쪽으로 한 칸 이동하기 (b3)
또 다른 예로 나이트가 c2에 위치해 있다면 나이트가 이동할 수 있는 경우의 수는 6가지이다. 이건 직접 계산해보시오.
<입력 조건>
첫째 줄에 8 X 8 좌표 평면상에서 현재 나이트가 위치한 곳의 좌표를 나타내는 두 문자로 구성된 문자열이 입련된다. 입력 문자는 a1처럼 열과 행으로 이뤄진다.
<출력 조건>
첫째 줄에 나이트가 이동할 수 있는 경우의 수를 출력하시오.

solution

# 현재 나이트의 위치 입력받기
input_data = input()
row = int(input_data[1])
column = int(ord(input_data[0])) - int(ord('a')) + 1

# 나이트가 이동할 수 있는 8가지 방향 정의
steps = [(-2,-1), (-1,-2), (1,-2), (2, -1), (2,1), (1,2),(-1,2),(-2,1)]

# 8가지 방향에 대하여 각 위치로 이동이 가능한지 확인
result = 0
for step in steps:
	# 이동하고자 하는 위치 확인
    next_row = row + step[0]
    next_column = column + step[1]
	# 해당 위치로 이동이 가능하다면 카운트 증가
    if next_row >= 1 and next_row <= 8 and next_column >= 1 and next_column <= 8:
    	result += 1
print(result)

실전문제 2 게임개발
현민이는 게임 캐릭터가 맵 안에서 움직이는 시스템을 개발 중이다. 캐릭터가 있는 장소는 1 X 1 크기의 정사각형으로 이뤄진 N X M 크기의 직사각형으로, 각각의 칸은 육지 또는 바다이다. 캐릭터는 동서남북 중 한 곳을 바라본다.
맵의 각 칸은 (A, B)로 나타낼 수 있고, A는 북쪽으로부터 떨어진 칸의 개수, B는 서쪽으로부터 떨어진 칸의 개수이다. 캐릭터는 상하좌우로 움직일 수 있고, 바다로 되어 있는 공간에는 갈 수 없다. 캐릭터의 움직임을 설정하기 위해 정해 놓은 매뉴얼은 이러하다.
현재 위치에서 현재 방향을 기준으로 왼쪽 방향(반시계 방향으로 90도 회전한 방향)부터 차례대로 갈 곳을 정한다.
캐릭터의 바로 왼쪽 방향에 아직 가보지 않은 칸이 존재한다면, 왼쪽 방향으로 횐전한 다음 왼쪽으로 한 칸을 전진한다. 왼쪽 방향에 가보지 않은 칸이 없다면, 왼쪽 방향으로 회전만 수행하고 1단계로 돌아간다.
만약 네 방향 모두 이미 가본 칸이거나 바다로 되어 있는 칸인 경우에는, 바라보는 방향을 유지한 채로 한 칸 뒤로 가고 1단계로 돌아간다. 단, 이때 뒤쪽 방향이 바다인 칸이라 뒤로 갈 수 없는 경우에는 움직임을 멈춘다.
현민이는 위 과정을 반복적으로 수행하면서 캐릭터의 움직임에 이상이 있는지 테스트하려고 한다. 메뉴얼에 따라 캐릭터를 이동시킨 뒤에, 캐릭터가 방문한 칸의 수를 출력하는 프로그램을 만드시오.
<입력 조건>
첫째 줄에 맵의 세로 크기 N과 가로 크기 M을 공백으로 구분하여 입력한다.
(3 <= N, M <= 50)
둘째 줄에 게임 캐릭터가 있는 칸의 좌표 (A, B)와 바라보는 방햔 d가 각각 서로 공백으로 구분하여 주어진다. 방향 d의 값으로는 다음과 같이 4가지가 존재한다.
0 : 북쪽
1 : 동쪽
2 : 남쪽
3 : 서쪽
셋째 줄부터 맵이 육지인지 바다인지에 대한 정보가 주어진다. N개의 줄에 맵의 상태가 북쪽부터 남쪽 순서대로, 각 줄의 데이터는 서쪽부터 동쪽 순서대로 주어진다. 맵의 외각은 항상 바다로 되어 있다.
0 : 육지
1 : 바다
처음에 게임 캐릭터가 위치한 칸의 상태는 항상 육지이다.
<출력 조건>
첫째 줄에 이동을 마친 후 캐릭터가 방문한 칸의 수를 출력한다.
<입력 예시>
4 4
1 1 0 // (1, 1)에 북쪽(0)을 바라보고 서 있는 캐릭터
1 1 1 1
1 0 0 1
1 1 0 1
1 1 1 1
<출력 예시>
3

solution

n, m = map(int, input().split())
x, y, d = map(int, input().split())
maps = []
for _ in range(n) :
  maps.append(list(map(int, input().split())))

dx=[-1,0,1,0]
dy=[0,-1,0,1]
count = 1

maps[x][y] = 2
turn_time = 0

def turn_left() :
  global d
  d += 1
  if d == 4 :
    d = 0

while True :
  turn_left()
  nx = x + dx[d]
  ny = y + dy[d] 
  
  if maps[nx][ny] == 0 :
    x, y = nx, ny
    count += 1
    turn_time = 0
    maps[nx][ny] = 2
  else :
    turn_time +=1

  if turn_time == 4 :
    nx = x - dx[d]
    ny = y - dy[d]
    if maps[nx][ny] == 1 :
      break
    else :
      x, y = nx, ny
    turn_time = 0

print(count)

출처
이것이 취업을 위한 코딩 테스트다 with 파이썬
저자 나동빈

이 글은 위 서적을 바탕으로 학습하기 위해 작성되었습니다.

profile
Not to be Number One, but to be Only One

0개의 댓글