-
1) 기업 코딩테스트 유형
- 삼성 : 어려운 구현 ex) 3190번: 뱀 (acmicpc.net), 14500번: 테트로미노 (acmicpc.net), 16236번: 아기 상어 (acmicpc.net)
- LG : 백트래킹, 완전탐색 ex) 14888번: 연산자 끼워넣기 (acmicpc.net), 10819번: 차이를 최대로 (acmicpc.net)
- 한화 : 구현, 동적계획법 ex) 1120번: 문자열 (acmicpc.net), 12865번: 평범한 배낭 (acmicpc.net)
- SK : 조합, 구현 ex) 10422번: 괄호 (acmicpc.net), 1759번: 암호 만들기 (acmicpc.net)
- 카카오 : 구현, DFS, BFS
- 네이버 : 구현, queue, 유니온 파인드
2) 시간복잡도
백준이나 프로그래머스 문제를 풀다 보면 심심치 않게 시간 초과 오류가 뜨는 것을 볼 수 있다.
왜 그럴까? 연산속도에 관련된 문제다. 일반적으로 1초에 1억 개의 연산을 할 수 있다. 물론 각 언어마다 같은 연산 횟수여도 시간은 다르지만 시험에선 이를 고려하기 때문에 결국 1억 이라는 연산 횟수가 중요합니다.
1억 번의 연산을 기준으로 잡고 문제를 해석한다면 해당 문제를 손쉽게 풀 수 있는 경우도 생길 수 있다.
예를 들어서 문제에서 조건으로 주어진 n의 범위가 1이상 100000이하라고 해보자 최악의 경우를 가정한 빅오 표기법으로 생각해 봤을 때 시간복잡도가 O(N^2)일 경우 연산횟수가 100억 번이 된다. 따라서 O(N^2)으로는 절대 풀 수 없다는 것을 의미한다. 그렇다면 이 문제는 O(N)이나 O(NlogN)으로 풀어야 한다는 이야기가 되고, 그러한 시간복잡도를 가진 알고리즘 풀이 방법을 좁힐 수 있게 된다.
경험상 n의 값이 10만 이상일 경우 이분탐색으로 푸는 문제가 90%였다.
3) 문제 풀이
https://www.acmicpc.net/problem/2805
2805번: 나무 자르기
첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000) 둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M보
www.acmicpc.net
n,m = map(int,input().split()) array = list(map(int,input().split())) def binary_search(start,end): if start > end: return start-1 mid = (start+end) // 2 sm = 0 for i in array: if i - mid >= 0: sm += i-mid if sm > m: return binary_search(mid+1,end) elif sm == m: return mid else: return binary_search(start,mid-1) print(binary_search(0,max(array)))
우선 이번 나무자르기 문제는 문제에서 조건이 1<=N<=1,000,000 입니다. 위에서 설명했듯이 N의 값이 10000이 넘어간다면 완전탐색 (일반적으로 시간복잡도 O(N^2)) 으로는 풀 수가 없습니다. 따라서 문제를 보자마자 이분탐색 혹은 정렬이라고 어느정도 예측을 하고 문제를 풀기 시작해야 합니다.
이분탐색 함수는 많이 사용되니 이해가 먼저고, 그 다음에 암기 하시면 좋습니다.
sm 은 자른 나무의 합을 넣는 sum 값을 넣는 변수입니다.
https://www.acmicpc.net/problem/2581
2581번: 소수
M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다. 단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.
www.acmicpc.net
import math def prime_number(num): if num == 2: return True elif num == 1: return False for i in range(2,int(math.sqrt(num))+1): if num % i == 0: return False return True M = int(input()) N = int(input()) sm = 0 mn = N+1 for i in range(M,N+1): if prime_number(i): sm += i mn = min(mn,i) if sm == 0: print(-1) else: print(sm) print(mn)
소수문제는 에라토스체네스의 체 알고리즘을 이용합니다. 지난 카카오 블라인드 1차 코테에서 나온 적이 있으니 선 이해후 암기하시면 됩니다!
여기서도 마찬가지로 sm은 소수의 sum을 나타내는 변수입니다. mn 은 min을 뜻하는 변수입니다.
만일 sm이 0이라면 소수가 발견되지 않았다는 말과 같으므로 -1을 출력했습니다.
2667번: 단지번호붙이기
<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여
www.acmicpc.net
n = int(input()) array = [] for _ in range(n): array.append(list(map(int,input()))) visit = [[False for _ in range(n)] for _ in range(n)] dx = [-1,0,1,0] dy = [0,1,0,-1] num = 1 def DFS(x,y): global num for i in range(4): nx = x + dx[i] ny = y + dy[i] if 0<=nx<n and 0<=ny<n: if visit[nx][ny] == False and array[nx][ny] == 1: visit[nx][ny] = True num += 1 DFS(nx,ny) total_num = 0 answer = [] for i in range(n): for j in range(n): if visit[i][j] == False and array[i][j] == 1: visit[i][j] = True total_num += 1 DFS(i,j) answer.append(num) num = 1 answer.sort() print(total_num) for i in answer: print(i)
여기서 num (각 구역마다 집의 개수) 를 함수 밖에서 선언해서 global로 받아오는게 중요합니다. DFS는 기본적으로 재귀를 통한 알고리즘이기때문에 함수 안에 선언할 경우 초기화되기 때문입니다. 또 여기서 사용하는 dx dy의 값은 0번째 인덱스부터 기준으로 북,동,남,서 를 의미합니다. 예를 들어서 북쪽으로 이동할경우 x는 x(기존 값) + dx[0] 이 되고 y는 y(기존값) + dy[0]입니다. x는 2차원 배열에서 위, 아래 / y는 2차원 배열에서 왼,오 를 뜻합니다.
DFS 알고리즘은 기본적으로 저런 형태로 기억하시면 좋습니다.
결과를 출력할 땐 오름차순으로 출력하기 때문에 answer.sort()를 해주고 이때 sort는 퀵소트와 버블소트를 합친 알고리즘으로 시간복잡도는 O(nlogn)입니다. 따라서 파이썬 내에서 정렬할 때 시간복잡도 상관없이 sort 쓰시면 됩니다.
코딩테스트 연습 - 오픈채팅방 | 프로그래머스 (programmers.co.kr)
코딩테스트 연습 - 오픈채팅방
오픈채팅방 카카오톡 오픈채팅방에서는 친구가 아닌 사람들과 대화를 할 수 있는데, 본래 닉네임이 아닌 가상의 닉네임을 사용하여 채팅방에 들어갈 수 있다. 신입사원인 김크루는 카카오톡 오
programmers.co.kr
def solution(record): # 아이디 : 이름 dic = {} for i in record: if 'Enter' in i or 'Change' in i: str1, str2, str3 = i.split(" ") # ex) Enter, uid1234, Muzi dic[str2] = str3 answer = [] for i in record: if 'Enter' in i: str1, str2, str3 = i.split(" ") answer.append(dic[str2]+"님이 들어왔습니다.") elif 'Leave' in i: str1, str2 = i.split(" ") answer.append(dic[str2]+"님이 나갔습니다.") return answer
우선 이 문제는 아이디에 따른 이름이 중요하므로 해쉬 테이블 (파이썬에서는 dict)를 사용했습니다.
이 문제에서 중요한건 파이썬 내에 있는 split이라는 내장함수인데, 만약 i = "Enter id1234 Muzi" 였다면
i.split(" ") 는 i를 " "로 구분한다는 의미 입니다. i안에 공백이 2개 있으므로 split으로 나누게 되면 총 3개로 나누어집니다. 따라서 3개의 변수로 이를 받아줘야하고 str1, str2, str3 = i.split(" ")에서
str1 = "Enter" , str2 = "id1234", str3 = "Muzi"가 됩니다.