기업 코딩 테스트 대비 노하우

Roeniss Moon·2020년 11월 20일
25

이 글은 backend roadmap for newcomer이라는, 교내 컴퓨터 동아리 저학년을 대상으로 한 발표 (내가 함) 자료 중 일부를 발췌, 각색하였음. 글쓴이의 지극히 개인적인 경험과 관측과 추론에 의지한 한없이 빈약한 플랜이므로, 반드시 별도의 교차검증 과정을 거치길 바람.

0. 기초 마인드셋을 갖춘다

"이것은 쎈수학 B 단계다"

라는 것을 명확히 인지하라. 기업에서 요구하는 문제의 수준은, 국내외 알고리즘 대회에서 요구하는 것에 한없이 못미치는 수준이다.

쎈수학을 풀어본 세대는 알겠지만 A 단계는 바로 앞 장에 있는 기초 개념만 외우면 바로바로 풀 수 있다. B 단계는 노력을 좀 해야 한다. 근데 C 단계는 갑자기 듣도보도 못한 (사실 언젠가 보긴 했었던) 개념을 가져와 요리조리 볶아 먹어야 풀 수 있다. 기업에서 요구하는 수준은 B 단계다. 절대 C 단계를 묻지 않는다. 그리고 쎈수학 B 단계는 분명히 '연습을 통해서 익숙해질 수 있다'.

"그 말을 증명할 수 있나?"

글쎄, 나는 아주 간접적인 증거들밖엔 없다. 예를 들면 이런거 :

백준 - 삼성 SW 역량 테스트 기출 문제 : 모든 문제가 골드 1 이하

백준 - 삼성 A형 기출 문제 : 모든 문제가 골드 1 이하

블로그 - SW 역량테스트 - 기출문제 목록 및 핵심 유형들 총정리!! (문제 풀이/해답/코드 : C++ / JAVA) : 한 문제가 플레티넘 5, 나머지 골드 1 이하

이 글을 작성하고 있는 2020년 가을 기준, 나올 수 있는 유형과 수준을 고려했을 때 모두 골드 3 이하 & 간혹 세게 나오는 문제 골드 1 정도로 예상된다. 아마 시간이 흐를 수록 상향 평준화 될 수도 있을 것 같은데 그런 '추세'가 보인다면 코멘트 하나만 달아주길 바란다.

중요한 것은 기업에서 요구하는 사람이 '천재' 내지는 '알고리즘 달인'이 아니라 '어느정도 많이 풀어본 학생'이라는 점, 그리고 반복하면 된다는 점에서 쎈수학 B 단계와 별반 차이가 없다는 것이다.

1. 최대한 자주 풀어라

양치기라고 불러도 좋다. 어쨌든 자주 풀어라.

양과 빈도는 개개인이 알아서 판단할 문제지만, 익숙해지지 않는다면 '시간을 정해놓고 푸는' 실전에서 (특히 첫 코테일 때) 매우 당황할 가능성이 크다.

기업 코테는, 쎈수학 B 단계이기 때문에, 문제를 보고 유형만 똑바로 파악하는 것이 매우 중요하며 바꿔 말하면 문제를 특정 유형이라고 빠르게 판단할 수 있다. 여기서 한 번 헛다리 짚을 때마다 N분씩 버리게 되는 것이다. 이 유형은 당연히, 해당 유형을 많이 풀어보면 도움이 될 것이다.

개인적으로는, DP를 판단하기가 제일 까다로운 것 같다. 예를 들면 이 문제를 보자 :

백준 - 파일 합치기(11066)

이 문제는, 물론 똑똑한 분들은 바로 DP임을 알 수 있겠지만 그렇지 않은 경우엔 몇 번의 시행 착오 내지는 시뮬레이션을 돌려봐야 한다. 하지만 DP를 많이 풀어본 사람은 N이 최대 500이고 파일 사이즈가 10000 이하임을 보고서 한 번에 DP까지 생각이 뻗을 수도 있다. 유형을 많이 풀어본다는 것은 그런 뜻이다. 눈치가 늘어난다는 것.

(물론 기업 코테는 일반적인 골드 난이도의 대회용 코딩 테스트 문제보다 느슨하고 허술한 구석이 많지만... 어쨌든)

2. 타겟 난이도를 명확히 하라

문제 간 난이도 선정의 미묘한 오차를 고려하여, 백준 기준 실버 3 ~ 골드 1의 문제를 막힘없이 풀 수 있으면 베스트라고 생각한다. 그 이상은 너무 과하며, 그 이하는 풀어도 의미가 없다.

당연한 얘기지만, 잘 안되면 브론즈 5부터 풀면 된다.

3. 너무 많이 고민하지 마라

특수한 케이스가 아니면 보통 취준, 프로젝트, 학업을 코테와 병행하게 된다. 그런데 이 코테는 러닝머신마냥 그냥 꾹 참고 하면 시간이 가는게 아니라서, 경우에 따라선 literally 30시간을 쏟아야 답에 이르는 경우도 있다. 이런 경우 기분이 매우 좋은게 사실이지만 이는 매우 비효율적인 전략이다. 시간이 넉넉치 않음을 생각하고, 항상 리미트를 정해두어야 한다.

'3시간 안에 답을 내지 못하면 답지를 보고 30분 내로 정답 판정을 받고 3일 뒤 다시 풀어보는' 333 전략을 권장한다. 쎈수학 B와 똑같지 않은가?

사실 30분 내로 정답을 맞추는 건 딱히 의미있는 부분은 아닌데 그냥 333 전략이라는 말을 쓰고 싶었다.

4. 문제를 빨리 풀 수 있는 환경을 세팅하라

사실 이 얘기가 하고 싶어서 어그로를 끌었다. 이 부분은 주관적인 이 글의 모든 부분 중 가장 주관적인 부분인데, 조금이라도 도움이 되었으면 좋겠다.

알고리즘 문제를 많이 풀다보면, 자꾸 같은 코드를 작성하는 경우가 생긴다. 예를 들면 :

  • (cpp) Visual Studio를 킬 때마다 상단에 using namespace std;를 친다.
  • (cpp) 출력할 때마다 cout << XXX << '\n' 또는 cout << XXX << endl를 친다.
  • (공통) 예제 입력을 넣고 결과를 확인할 때 코드를 돌리고, 예제 인풋을 복사해서, 콘솔창에 붙여넣기 한다.
  • (파이썬) priority_queue같은 내장 라이브러리를 쓸 때마다 import한다.
  • ...

이런 경우는 보통 불편해지기 전에 익숙해져버려서, 굳이 개선할 필요성을 느끼지 못한다. 하지만 미리 템플릿을 만들어두면 어떨까? 템! 플! 릿!

나는 https://gist.github.com 에 템플릿 코드를 만들어두고, 필요할 때마다 수정하면서 내게 필요한 매크로를 추가하는 방식으로 사용한다. 나는 언제 어디서나 새 문제를 풀 때 이 코드를 복사해놓고 시작한다. 나에겐 이보다 익숙한 도구가 없으며, 다른 고수들의 정답 코드를 보면 알겠지만, 이건 매우 기초적인 수준이다.

별(⭐️) 마크는 이 코드가 난해한 분들을 위한 추가 주석이다.

// https://gist.github.com/roeniss/802f851654d12d9106647f28f5dbe3e3 - main.cpp
// ⭐️ 파이썬도 만들어 보려고 했는데, 계속 cpp만 하게 되는 것 같음...

// 파도가 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊 철썩 철썩 // ⭐️ 별 의미 없다
#include <iostream>
#include <deque>
#include <vector>
#include <queue>
#include <algorithm> // ⭐️ 이 정도 라이브러리만 받아두면 내가 푸는 문제 선에서는 충분했다

using namespace std;

#define ffor(i, x) for (int (i) = 0; (i) < (x) ; ++(i)) // ⭐️ 0부터 x-1까지 for-loop
#define fffor(i, x) for (int (i) = 1; (i) <= (x) ; ++(i)) // ⭐️ 1부터 x까지 for-loop
#define cc(x) cin >> (x); // ⭐️ stdin 인풋 하나 받기
#define ccc(x) int (x); cin >> (x); // ⭐️ int 변수 만들고 그걸로 stdin 인풋 하나 받기
#define coo(x) cout << x << '\n'; // ⭐️ 변수 출력하고 줄바꿈
#define cob(x) cout << x << ' '; // ⭐️ 변수 출력하고 스페이스바
#define ii pair<int, int> // ⭐️ 보통 vector랑 많이 쓴다
#define ll long long // ⭐️ 매번 long long 치고 있으면 현기증이 옴

int dx[] = {1, 0, -1, 0}; // 동 남 서 북 // ⭐️ DFS, BFS 문제 풀 때 꼭 씀
int dy[] = {0, 1, 0, -1}; // ⭐️ 이렇게 안하고 2x4 배열로 만들어 쓰는 사람들도 있는 것 같다
int INF = 1e9 + 7; // ⭐️ 의외로 자주 쓰는 수. 자주 쓰고 말고는 문제를 풀면서 생각해보면 될 문제
// 파도가 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊 철썩 철썩



int main() {
    // 파도가 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊 철썩철썩 @formatter:off // ⭐️ 나는 Jetbrains의 CLion을 쓰는데, 이 코드 이후로는 reformat(줄 정렬)을 안한다. 자꾸 이상하게 줄을 맞춰주길래 해제함.
    ios_base::sync_with_stdio(false); // ⭐️ cpp 필수1
    cout.tie(nullptr); // ⭐️ cpp 필수2
    cin.tie(nullptr); // ⭐️ cpp 필수3
#ifndef ONLINE_JUDGE // ⭐️ ONLINE_JUDGE 라는 값이 없다면 endif 가 나올 때까지 아래 코드를 사용한다. 이 값은 백준 서버에서 코드를 돌릴 때 자동으로 설정된다. 따라서 이 아래 freopen 두 줄은 로컬에서만 적용된다.
    freopen("tc.txt", "r", stdin); // ⭐️ tc.txt 라는 파일에 예제 입력을 복붙해 두면 이후 코드 실행할 때마다 콘솔에 매번 입력하지 않고 자동으로 파일을 읽어서 결과를 출력한다.
    // freopen("result.txt", "w", stdout); // ⭐️ 위와 비슷하게, 출력 결과를 콘솔 대신 result.txt 로 뽑아내 저장하는 것이다. 보통 출력이 너무 길어서 읽기 힘들 때 사용한다.
#endif // 파도가 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊 철썩철썩 @formatter:on // ⭐️ 여기 이후론 reformat 적용

  // ⭐️ 아래는 예제 코드
  ccc(tc) // 테스트 케이스 갯수 입력 받기
  int arr[10000], map[10000][10000];
  while(tc--){ // 각 테스트 케이스마다
     ccc(len) // 인풋 갯수 받기
     ffor(i, len) { // 인풋 갯수만큼 for-loop
       cc(arr[i]) // 각 인풋을 배열 각 인덱스에 삽입
       ffor(j, len) map[i][j] = 0; // 하는 김에 map 초기화 (for-loop)
     }
     
     ffor(i, len) coo(arr[i]) // 한 줄에 하나씩 배열값 출력
  }


}

이렇게 만들어놓고 익숙해지면 매번 치는 코드를 획기적으로 단축할 수 있다.

이와 관련해서, 사실 진짜 좋은 문제 풀이 기법 중 하나는 온라인 저지(ex. 백준) 문제를 푼 뒤 그 언어로 푼 답변 중 상위권에 있는 답을 보는 것이다. 그 풀이들은 단순히 문제를 푼 것 뿐만 아니라 더 빨리, 더 효율적으로, 더 적은 메모리로, 해당 언어의 모든 장점을 살려서 만들어낸 풀이이기 때문에 문제를 푸는 것만큼 재밌지는 않지만 많은 도움이 된다.

profile
기능이 아니라 버그예요

4개의 댓글

comment-user-thumbnail
2020년 12월 15일

Hello, I enjoy reading all of your article. I like to write a little comment to support you.JOKER123

1개의 답글
comment-user-thumbnail
2021년 3월 18일

쎈수학ㅋㅋ 무슨느낌인지 바로 알겠어요! 감사합니다😁

1개의 답글