꺼내먹는지식 준

구현 본문

코딩테스트총정리

구현

알 수 없는 사용자 2022. 8. 2. 15:59

구현이란 '머리속에 있는 알고리즘을 소스코드로 바꾸는 과정' 이다. 

즉, 1) 문제를 보고 2) 풀이를 떠올리고, 3) 소스코드로 옮겨야 한다. 

즉, 마치 게임에서 손 빠른 사람을 '피지컬'이 좋다고 하듯이, 구현 유형 문제는 소스 코드로 구현을 하는 코딩 '피지컬'을 요구한다고 볼 수 도 있다. 

 

소스코드로 옮기는 과정이 원할하기 위해서는 기본적으로 다음의 능력이 필요하다. 

1) 충분한 라이브러리 사용 경험 

2) 충분한 문법 숙지 

 

완전 탐색과 시뮬레이션은 구현에 포함한다고 가정하였다. 

때로 기업 공채에서는 웹 서버나 데이터 분석 기초 지식이 필요하기도 하다. 

 

몇개의 구현 알고리즘을 풀어보자. 

 

1) 상하좌우 

N X N 정사각형의 한 블럭(1 X 1)위에 여행가가 서 있다. 가장 왼쪽  (1,1) 가장 오른쪽 하단을 (N,N)이라 하고 여행가는 (1,1)에서 시작하여 상하좌우(U,D,L,R)로 이동할 수 있다. 주어진 여행 계획서에 따라 이동하자. 

N X N 정사각형 크기를 벗어나는 움직임은 무시 된다. 최종 도착 지점을 찾아라. 

 

import sys 
input = sys.stdin.readline

N = int(input())
lst = input().split()

x,y = 1,1 
direction = {'L': [0, -1], 'R': [0, 1], 'U': [-1,0], 'D': [1,0]}

for c in lst:
    dx, dy = direction[c]
    if x + dx < 1 or y + dy < 1 or x + dx > 5 or y + dy > 5:
        continue
    else:
        x += dx 
        y += dy

print(x, y)

 

2) 시각 

00시 00분 00초부터 N시 59분 59초까지 모든 시각 중 3이 하나라도 포함되는 모든 경우의 수를 구하는 프로그램을 작성하자. 입력은 N 이다. 

 

import sys 
input = sys.stdin.readline

N = int(input())

def one_hour(n):
    cnt = 0
    m = 0 
    for i in range(60):
        s = 0
        for j in range(60):
            if '3' in str(100 * m + s):
                cnt += 1 
            s += 1 
        m += 1
    cnt *= n 
    return cnt 

if N < 3:
    print(one_hour(N+1))
else:
    print(one_hour(N) + 60*60)

3시를 제외하고는 반복이기에 00시 00분 00초부터 00시 59분 59초까지 구한 값에 N 배해주면 되고, 3시인 경우에만 계속 3이 포함되므로 개수가 60 * 60 이다. 

 

00시 00분 00초 부터 23시 59분 59초까지 경우의 수가 86,400 개밖에 안되므로 그냥 3중 for 문으로 작성해도 별 문제는 없다. 

그리고 나처럼 수를 수로 보고 더하지 않고 

for i in range(60):
	for j in range(60):
    	if '3' in str(i) + str(j):
        	cnt +=1

str 처리해서 더해도 순서가 유지됨을 기억하자. 

 

3) 왕실의 나이트 

8 X 8 좌표 평면이 주어졌다. 특정 한 칸에 나이트가 서 있다. 나이트는 좌표 평면 밖으로는 나갈 수 없다. 

나이트 위치가 주어졌을 때, 나이트가 이동할 수 있는 경우의 수를 출력하자. 

행은 1 ~ 8, 열은 a ~ h 이다. 

 

import sys 
input = sys.stdin.readline

tmp = input()
column, row = tmp[0], int(tmp[1])

column = ord(column) - 96 

knight = [[2,1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2]]

cnt = 0

for dx, dy in knight:
    if column + dx < 1 or column + dx > 8 or row + dy < 1 or row + dy > 8:
        continue
    else: 
        cnt +=1 

print(cnt)

 

ord(column) - 96 의 경우 ord('a')값이 기억이 나지 않을 수 있다. 

이를 위해 

column = ord('column') - ord('a') + 1

으로 하면 더 쉽게 기억 할 수 있다. 

list of list 로 하지말고 sets in list 로 하자. 

 

4) 게임 개발 

맵은 N X M (육지와 바다 존재), 캐릭터는 1 X 1 크기를 차지한다. 맵의 각 칸은 (A, B)로 나타낸다. 왼쪽 상단이 (0,0) 이다. 

캐릭터는 상하좌우로 움직일 수 있고, 바다 공간은 갈 수 없다. 다음의 메뉴얼을 따른다.

 

1) 현재 위치, 방향 기준 왼쪽 방향 부터 차례대로 갈 곳을 정한다. 

2) 캐릭터의 바로 왼쪽 방향에 아직 가보지 않은 칸 존재시, 왼쪽 방향으로 회전 후 왼쪽으로 한칸 전진한다. 왼쪽 방향에 가보지 않은 칸이 없으면 왼쪽 방향으로 회전만 수행하고 1단계로 돌아간다. 

3) 만약 네 방향 모두 이미 가본 칸이거나 바다로 되어 있는 경우, 바라보는 방향을 유지한 채 한칸 뒤로 가고 1단계로 돌아간다. 만약 뒤쪽 방향이 바다라면 움직임을 멈춘다. 

(바다 1 육지 0)

캐릭터가 방문한 칸의 수를 구하여라. 

import sys 
input = sys.stdin.readline

row, column = map(int, input().split())

y, x, dir = map(int, input().split())

map_ = []
for i in range(row): 
    map_.append( list(map(int, input().split())) )

change = {0: 3, 1: 0, 2: 1, 3: 2}

go = {0 : (-1, 0), 1: (0, 1), 2: (1, 0), 3: (0, -1)}

visited= [[0]*5 for i in range(5)]
visited[y][x] = 1 
print("visited", visited)
#visited = [[0] * column] * row  이거 절대 안됨 


while(True):
    for i in range(4):
        dir = change[dir]
        dy, dx = go[dir]
        if dx + x < 0 or dy + y < 0 or dx + x > column or dy + y > row:
            continue
        elif map_[dy+y][dx+x] == 1:
            continue
        else:
            if visited[y+dy][x+dx] == 0:
                x += dx
                y += dy
                visited[y][x] = 1 
                print("visited: ", visited)

            else: 
                continue
            break
    else:
        #4번의 시도를 실패한 경우 바라보는 방향의 뒤로 가기 
        dy, dx =  go[dir]
        x -= dx 
        y -= dy 
        if map_[y][x] == 1: #뒤로 돌아 간 곳이 바다면 stop 
            break 
        visited[y][x] = 1  # 처음부터 뒤로 가는 경우에는 방문하지 않았을 수도 있다. 
        print("visited: ", visited)

    
print(sum([sum(i) for i in visited]))
#sum(map(sum, visited))

 

정답과 비교했을 때 유의점 

 

1. 왼쪽으로 회전을 나의 경우 dictionary 로 정의했는데 잘 살펴보면 사실상 방향의 value 가 1씩 낮아지다가 -1 될 때 3이 된다. 

def turn_left():
    direction -= 1 
    if direction == -1:
        direction = 3

위와 같이 처리해도 된다. 하지만 이 경우 dictionary 가 좀 나았던 것으로 보인다. 

 

동서남북 방향 정의를 내 경우 

특정 방향일 때 한번에 가독성이 좋도록 dictionary 를 사용했다. 

go = {0 : (-1, 0), 1: (0, 1), 2: (1, 0), 3: (0, -1)}

반면 정답은 아래와 같이 처리했다. 

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

사실상 완전 같지만, 아래처럼 처리하는 것도 눈에 익혀야겠다. 

 

내 경우 4번 돌다가, 앞으로 전진이 가능한 경우 break 로 빠져나오고 못 빠져나온 경우 for 문의 else 로 들어가도록 처리했다. 

 

하지만, 정답의 경우 turn_time 이라는 변수를 하나 놓고 turn_time 이 4가 될 때 까지 돌면서 전진 가능한지 확인하도록 했다. 

사실상 같은 방식이지만, 개인적으로는 내 방식이 가독성이 좀더 높다고 생각한다. 다만 정답 방식이구현시 실수가 더 적을 것 같다. 

 

그리고 정답은 count 를 직접했다. 해당 방법의 발생 가능한 문제는 시작 지점에서 갈 수 있는 곳이 없어 뒤로 갈 경우, 도착 지점이 방문 한적이 없을 때 count 를 +1 해줄 수 없다는 단점이 있다. 이 경우 count 를 사용한다면 manual 하게 뒤로 돌아 도착한 곳도 방문 한적이 있나 확인해주고 더해주면 되긴하다. 

memory 면에서 count 를 사용하는 것이 더 효율적으로 보인다. 

 

※ 실수하기 좋은 것 

visited = [[0] * 5 for i in range(4)]

[[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

 

visited = [[0]* 5] * 4

[[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

 

둘의 출력결과는 같으나 이는 대 참사를 불러일으킬 수 있다 .

아래의 visited = [[0]*5] * 4 는 

[0,0,0,0,0] 를 5번 깊은 복사하여 한 list의 element 를 수정할시 각 list 마다 모두 반영이 된다. 

 

 

 

'코딩테스트총정리' 카테고리의 다른 글

정렬  (0) 2022.08.03
DFS, BFS  (0) 2022.08.03
그리디  (0) 2022.07.29
프로그래머스 stack 짝지어 제거하기  (0) 2022.05.07
HEAP  (0) 2022.05.05
Comments