기술면접 질문 정리 알고리즘
카테고리: CS
태그: 면접질문
동적 계획법(DP, Dynamic Programming)에 대해 설명하시오.
주어진 문제를 풀기 위해, 문제를 여러 개의 하위 문제로 나누어 푸는 방법을 말한다.
동적 계획법에서는 어떤 부분 문제가 다른 문제들을 해결하는데 사용될 수 있어, 답을 여러 번 계산하는 대신 한 번만 계산하고
그 결과를 재활용하는 메모이제이션(Memoization)기법으로 속도를 향상시킬 수 있다.
※ 메모이제이션 : 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 재사용함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술
동적 계획법(DP, Dynamic Programming)이 갖는 2가지 조건은 무엇인가?
-
중복되는 부분(작은) 문제
중복되는 부분 문제는 나눠진 부분 문제가 중복되는 경우로, 메모이제이션 기법을 사용해 중복 계산을 없앤다. -
최적 부분 구조
최적 부분 구조를 가진다는 것은 전체 문제의 최적해가 부분 문제의 최적해들로써 구성된다는 것이다.
버블 정렬(Bubble Sort)에 대해 설명하시오.
버블 정렬는 서로 인접한 두 원소를 비교하여 정렬하는 알고리즘이다.
0번 인덱스부터 n-1번 인덱스까지 n번까지의 모든 인덱스를 비교하며 정렬합니다. 시간 복잡도는 O(n^2)이다.
선택 정렬(Selection Sort)에 대해 설명하시오.
선택 정렬은 첫 번째 값을 두번째 부터 마지막 값까지 차례대로 비교하여 최솟값을 찾아 첫 번째에 놓고,
두 번째 값을 세 번째 부터 마지막 값까지 비교하여 최솟값을 찾아 두 번째 위치에 놓는 과정을 반복하며 정렬하는 알고리즘입니다. 시간복잡도는 O(n^2)이다.
삽입 정렬(Injection Sort)에 대해 설명하시오.
삽입 정렬은 두 번째 값부터 시작해 그 앞에 존재하는 원소들과 비교하여 삽입할 위치를 찾아 삽입하는 정렬 알고리즘이다.
평균 시간복잡도는 O(n^2)이며, Best Case 의 경우 O(n)까지 높아질 수 있다.
힙 정렬(Heap Sort)에 대해 설명하시오.
힙 정렬은 주어진 데이터를 힙 자료구조로 만들어 최댓값 또는 최솟값부터 하나씩 꺼내서 정렬하는 알고리즘이다.
힙 정렬이 가장 유용한 경우는 전체를 정렬하는 것이 아니라 가장 큰 값 몇개만을 필요로 하는 경우이다.
시간 복잡도는 O(nlogn)이다.
병합 정렬(Merge Sort)에 대해 설명하시오.
병합 정렬은 주어진 배열을 크기가 1인 배열로 분할하고 합병하면서 정렬을 진행하는 분할/정복 알고리즘이다.
시간 복잡도는 O(nlogn)이다.
퀵 정렬(Quick Sort)에 대해 설명하시오.
퀵 정렬은 빠른 정렬 속도를 자랑하는 분할 정복 알고리즘 중 하나로 피봇을 설정하고 피봇보다 큰 값과 작은 값으로 분할하여 정렬 한다.
병합정렬과 달리 리스트를 비균등하게 분할한다.
시간 복잡도는 O(nlogn)이며 worst case 경우 O(n^2)까지 나빠질 수 있다.
정렬 알고리즘 시간 복잡도 비교 표
Big-O 표기법의 시간 복잡도 크기 순서를 말하시오.
O(1) < O(log N) < O(N) < O(N log N) < O(N^2) < O(2^N) < O(N!)
허프만 코딩에 대해 설명하시오.
허프만 코딩은 문자의 빈도 수를 가지고 압축하는 과정을 말하며, 접두부 코드와 최적 코드를 사용한다.
접두부 코드 : 각 문자에 부여된 이진 코드가 다른 이진 코드의 접두부가 되지 않는 코드 (즉, 겹치지 않도록 이진 코드를 만드는 것) 최적 코드 : 인코딩된 메시지의 길이가 가장 짧은 코드
재귀 알고리즘에 대해 설명하시오.
재귀 알고리즘이란 함수 내부에서 함수가 자기 자신을 또 다시 호출하여 문제를 해결하는 알고리즘이다.
자기자신을 계속해서 호출하여 끝없이 반복되게 되므로 반복을 중단할 조건이 반드시 필요하다.
피보나치 수열의 N번째 값을 구하는 메소드에 대해 각각 재귀와 반복문으로 손코딩(또는 수도코딩) 하시오.
private static int recursiveFibonacci(int index) {
if (index <= 2){
return 1;
}
return recursiveFibonacci(index - 1) + recursiveFibonacci(index - 2);
}
private static int loopFibonacci(int index) {
int answer = 1;
int before = 1;
int temp;
for (int i = 2; i < index; i++) {
temp = answer;
answer += before;
before = temp;
}
return answer;
}
팩토리얼의 N번째 값을 구하는 메소드에 대해 각각 재귀와 반복문으로 손코딩(또는 수도코딩) 하시오.
private static int recursiveFactorial(int num) {
if(num > 1) {
return recursiveFactorial(num -1) * num;
}
return 1;
}
private static int loopFactorial(int num) {
int answer = 1;
for(int i = 2; i <= num; i++) {
answer *= i;
}
return answer;
}
코딩 테스트를 위한 Tip
Translate this article: How to Rock an Algorithms Interview
-
칠판에 글쓰기를 시작하시오. 이것은 당연하게 들릴지 모르지만, 빈 벽을 쳐다 보면서 수십 명의 후보자가 붙어 있다. 나는 아무것도 보지 않는 것보다 문제의 예를 응시하는 것이 더 생산적이라고 생각한다. 관련성이있는 그림을 생각할 수 있다면 그 그림을 그린다. 중간 크기의 예제가 있으면 작업 할 수 있다. (중간 크기는 작은 것보다 낫다.) 때로는 작은 예제에 대한 솔루션이 일반화되지 않기 때문이다. 또는 알고있는 몇 가지 명제를 적어 두시오. 뭐라도 하는 것이 아무것도 안 하는 것보다 낫다.
-
그것을 통해 이야기하시오. 자신이 한 말이 어리석은 소리일까 걱정하지 마시오. 많은 사람들이 문제를 조용히 생각하는 것을 선호하지만, 문제를 풀다가 막혔다면 말하는 것이 한 가지 방법이 될 수 있다. 가끔은 면접관에게 진행 상황에 대해서 명확하게 말하는 것이 지금 문제에서 무슨 일이 일어나고 있는지 이해할 수 있는 계기가 될 수 있다. 당신의 면접관은 당신이 그 생각을 추구하도록 당신을 방해 할 수도 있다. 무엇을 하든지 힌트를 위해 면접관을 속이려 하지 마시오. 힌트가 필요하면 정직하게 질문하시오.
-
알고리즘을 생각하시오. 때로는 문제의 세부 사항을 검토하고 해결책이 당신에게 나올 것을 기대하는 것이 유용하다 (이것이 상향식 접근법 일 것입니다). 그러나 다른 알고리즘에 대해서도 생각해 볼 수 있으며 각각의 알고리즘이 당신 앞의 문제에 적용되는지를 질문 할 수 있다 (하향식 접근법). 이러한 방식으로 참조 프레임을 변경하면 종종 즉각적인 통찰력을 얻을 수 있다. 다음은 면접에서 요구하는 문제의 절반 이상을 해결하는 데 도움이되는 알고리즘 기법이다.
- Sorting (plus searching / binary search)
- Divide and Conquer
- Dynamic Programming / Memoization
- Greediness
- Recursion
- Algorithms associated with a specific data structure (which brings us to our fourth suggestion…)
- 데이터 구조를 생각하시오.
상위 10 개 데이터 구조가 실제 세계에서 사용되는 모든 데이터 구조의 99 %를 차지한다는 것을 알고 계셨습니까? 때로는 최적의 솔루션이 블룸 필터 또는 접미어 트리를 필요로하는 문제를 묻는다. 하지만 이러한 문제조차도 훨씬 더 일상적인 데이터 구조를 사용하는 최적의 솔루션을 사용하는 경향이 있습니다. 가장 자주 표시 될 데이터 구조는 다음과 같다.
- Array
- Stack / Queue
- HashSet / HashMap / HashTable / Dictionary
- Tree / Binary tree
- Heap
- Graph
-
이전에 보았던 관련 문제와 해결 방법에 대해 생각해보시오. 여러분에게 제시한 문제는 이전에 보았던 문제이거나 적어도 조금은 유사하다. 이러한 솔루션에 대해 생각해보고 문제의 세부 사항에 어떻게 적응할 수 있는지 생각하시오. 문제가 제기되는 형태로 넘어지지는 마시오. 핵심 과제로 넘어 가서 과거에 해결 한 것과 일치하는지 확인하시오.
-
문제를 작은 문제로 분해하여 수정하시오. 특별한 경우 또는 문제의 단순화 된 버전을 해결하시오. 코너 케이스를 보는 것은 문제의 복잡성과 범위를 제한하는 좋은 방법이다. 문제를 큰 문제의 하위 집합으로 축소하면 작은 부분부터 시작하여 전체 범위까지 작업을 진행할 수 있다. 작은 문제의 구성으로 문제를 보는 것도 도움이 될 수 있다.
- 되돌아 오는 것을 두려워하지 마시오. 특정 접근법이 효과적이지 않다고 느끼면 다른 접근 방식을 시도 할 때가 있다. 물론 너무 쉽게 포기해서는 안된다. 그러나 열매를 맺지 않고도 유망한 생각이 들지 않는 접근법에 몇 분을 소비했다면, 백업하고 다른 것을 시도해보시오. 저는 덜 접근한 지원자보다 한참 더 많이 나아간 지원자를 많이 보았다. 즉, (모두 평등 한) 다른 사람들이 좀 더 기민한 접근 방식을 포기해야 한다는 것을 의미한다.
문제 해결을 위한 전략적 접근
코딩 테스트의 목적
- 문제 해결 여부
- 예외 상황과 경계값 처리
- 코드 가독성과 중복 제거 여부 등 코드 품질
- 언어 이해도
- 효율성 궁극적으로는 문제 해결 능력을 측정하기 위함이며 이는 ‘어떻게 이 문제를 창의적으로 해결할 것인가’를 측정하기 위함이라고 볼 수 있다.
접근하기
- 문제를 공격적으로 받아들이고 필요한 정보를 추가적으로 요구하여, 해당 문제에 대해 완벽하게 이해하는게 우선이다.
- 해당 문제를 익숙한 용어로 재정의하거나 문제를 해결하기 위한 정보를 추출한다. 이 과정을 추상화라고 한다.
- 추상화된 데이터를 기반으로 이 문제를 어떻게 해결할 지 계획을 세운다. 이 때 사용할 알고리즘과 자료구조를 고민한다.
- 세운 계획에 대해 검증을 해본다. 수도 코드 작성도 해당될 수 있고 문제 출제자에게 의견을 물어볼 수도 있다.
- 세운 계획으로 문제를 해결해본다. 해결이 안 된다면 앞선 과정을 되짚어본다.
생각할 때
- 비슷한 문제를 생각해본다.
- 단순한 방법으로 시작하여 점진적으로 개선해나간다.
- 작은 값을 생각해본다.
- 그림으로 그려본다.
- 수식으로 표현해본다.
- 순서를 강제해본다.
- 뒤에서부터 생각해본다.
댓글남기기