해당 프로젝트에서는 코딩테스트 학습을 위하여 JVM 기반 언어의 코딩테스트 문제 풀이를 진행한다.
- 문제를 읽고 이해한다.
- 문제를 익숙한 용어로 재정의한다.
- 어떻게 해결할지 계획을 세운다.
- 계획을 검증한다.
- 프로그램으로 구현한다.
- 어떻게 풀었는지 돌아보고, 개선할 방법이 있는지 찾아본다.
- 문제를 어떤 방식으로 접근했는지, 문제의 해법을 찾는 데 결정적이였던 깨달음은 무엇이였는지 반드시 기록한다.
- 문제들 간에 공통으로 필요한 통찰의 패턴을 찾기 위함.
- 문제를 한 번에 맞추지 못한 경우 오답 원인을 기록한다.
- 실수를 반복하는 부분을 찾기 위함.
- 한 문제에 30분 이상 소요하지 않는다.
- 문제풀이에 30분 이상 소요될 경우 다른 사람의 소스 코드나 풀이를 참조한다.
- 내가 문제를 해결할 때 취했던 접근들을 되새겨보며 왜 이 풀이를 떠올리지 못했는지 살펴본다.
자바 언어를 사용하는 경우, java-coding-test
모듈 내부에 새로운 문제에 대한 모듈을 추가하여 문제 풀이를 수행한다.
코틀린 언어를 사용하는 경우, kotlin-coding-test
모듈 내부에 새로운 문제에 대한 모듈을 추가하여 문제 풀이를 수행한다.
이러한 방식으로 새로운 언어를 사용하고자 하는 경우, {언어}-coding-test
라는 모듈을 만들고 모듈 내부에 새로운 문제에 대한 모듈을 추가하여 문제 풀이를 수행한다. (다만 JVM 기반에서 구동되는 언어여야 함.)
디렉터리 구조로 예시를 들면 아래와 같다.
└──/coding-test
├──/java-coding-test
│ ├──/coding-test-1
│ └──/coding-test-2
│
├──/kotlin-coding-test
│ ├──/coding-test-1
│ └──/coding-test-2
│
├──/scala-coding-test
│ ├──/coding-test-1
│ └──/coding-test-2
.
.
.
이런 방식을 채용하는 이유는, 각 문제별로 독립된 상태로 구동 가능하도록 하기 위함이다.
main 메서드 상단에는 문제 내용을 주석으로 작성한다.
예시 :
/**
* 문자 찾기.
*
* 설명 :
* 한 개의 문자열을 입력받고, 특정 문자를 입력받아 해당 특정문자가 입력받은 문자열에 몇 개 존재하는지 알아내는 프로그램을 작성하세요.
*
* 입력 :
* 첫 줄에 문자열이 주어지고, 두 번째 줄에 문자가 주어집니다.
* 문자열은 영어 알파벳으로만 구성되어 있습니다.
*
* 출력 :
* 첫 줄에 해당 문자의 개수를 출력합니다.
*
* 예시 입력 1 :
* Computercooler
* c
*
* 예시 출력 1 :
* 2
*/
만약, 문제 내용에 이미지가 포함되어있거나 혹은 텍스트로 문제 내용을 모두 전달하기 어렵다면,
모듈 내부에 quiz라는 이름으로 문제를 markdown 형식으로 작성하여 첨부한다.
디렉터리 구조로 예시를 들면 아래와 같다.
└──/coding-test
├──/java-coding-test
│ └──/coding-test-1
│ ├──quiz.md # 문제 설명 markdown
│ └──CodingTest1.java # 문제 해결 코드
.
.
.
main 메서드 하단에는 문제 풀이에 대한 회고를 작성한다.
문제 풀이 회고에 대한 형식은 아래와 같다. :
/**
* 문제 풀이 시작 시간 : yyyy-MM-dd HH:mm:ss
* 문제 풀이 종료 시간 : yyyy-MM-dd HH:mm:ss
*
* 문제를 어떤 방식으로 접근했는지, 문제의 해법을 찾는 데 결정적이였던 깨달음은 무엇이였는지?
* -
*
* 문제를 한 번에 맞추지 못한 경우 오답 원인이 무엇이였는지?
* -
*
* */
아래는 문제 풀이 방식 예시이다. :
public class WordsInSentence {
/**
* 문장 속 단어.
*
* 한 개의 문장이 주어지면 그 문장 속에서 가장 긴 단어를 출력하는 프로그램을 작성하세요.
* 문장속의 각 단어는 공백으로 구분됩니다.
*
* 입력 :
* 첫 줄에 길이가 100을 넘지 않는 한 개의 문장이 주어집니다.
* 문장은 영어 알파벳으로만 구성되어 있습니다.
*
* 출력 :
* 첫 줄에 가장 긴 단어를 출력합니다.
* 가장 길이가 긴 단어가 여러개일 경우 문장속에서 가장 앞쪽에 위치한 단어를 답으로 합니다.
*
* 예시 입력 1 :
* it is time to study
*
* 예시 출력 1 :
* study
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String sentence = sc.nextLine();
String[] words = sentence.split(" ");
// for-loop 사용
String result = words[0];
for (String str: words) {
if(str.length() > result.length()) {
result = str;
}
}
System.out.println(result);
// Stream 사용
// 성능이 더 안좋음.
// 또한 reversed 때문에 "가장 길이가 긴 단어가 여러개일 경우 문장속에서 가장 앞쪽에 위치한 단어를 답으로 합니다" 조건이 만족 안될 수 있음.
// String result = Arrays.stream(words).sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList()).get(0);
// System.out.println(result);
}
/**
* 문제 풀이 시작 시간 : 2021-12-24 10:00:00
* 문제 풀이 종료 시간 : 2021-12-24 10:15:00
*
* 문제를 어떤 방식으로 접근했는지, 문제의 해법을 찾는 데 결정적이였던 깨달음은 무엇이였는지 ?
* - 문자열을 입력 받을 때, 공백 기준으로 split 처리한 결과를 단순하게 문자열 길이 기준으로 내림차순 정렬하면 좀 더 빠르게 결과를 찾을 수 있지 않을까 생각하게 되었음.
* - 하지만, "가장 길이가 긴 단어가 여러개일 경우 문장속에서 가장 앞쪽에 위치한 단어를 답으로 합니다" 라는 기준에 의해 정렬을 하면 요구사항을 충족하지 못할 가능성이 생김.
* - 따라서 단순하게 for-each를 사용하여 공백 기준으로 split 처리한 결과에서 가장 긴 문자열을 result라는 String 타입 변수에 갱신하도록 처리함.
* - 문자 갯수에 대해서 O(n)의 시간복잡도를 가짐.
*
* 문제를 한 번에 맞추지 못한 경우 오답 원인이 무엇이였는지?
* - 처음에 Java Stream 기능을 활용하여 문자 배열을 정렬하여 단순하게 처리하려 하였으나,
* - "가장 길이가 긴 단어가 여러개일 경우 문장속에서 가장 앞쪽에 위치한 단어를 답으로 합니다" 라는 기준에 의해 정렬을 하면 요구사항을 충족하지 못할 가능성이 생기는 것을 알아차렸다.
* - 그래서 다시 for-each를 사용하여 처리하도록 개선하였다.
*
* */
}
코딩테스트 학습에 도움이 되는 글을 정리하여 아래 링크에 정리한다.
꾸준히 참고하여 실력을 높여보자.