자료구조/알고리즘 신입 성능 최적화 면접
새 면접Q. 사용자 목록을 순회하면서 각 사용자마다 전체 상품 목록을 다시 순회하는 코드가 있습니다. 사용자가 1000명, 상품이 1000개일 때 성능 문제가 발생했습니다. 이 코드의 시간복잡도는 무엇이며, 왜 성능 문제가 발생하는지 설명해주세요.
중첩된 반복문의 시간복잡도를 생각해보세요.
이 코드의 시간복잡도는 O(N×M)입니다. 사용자 수(N)와 상품 수(M)를 각각 곱한 만큼 연산이 발생하므로, 1000×1000 = 100만 번의 연산이 실행됩니다. 중첩 반복문은 데이터가 증가할수록 연산 횟수가 기하급수적으로 늘어나기 때문에 성능 병목이 발생합니다. 이를 개선하려면 해시맵이나 인덱싱을 활용해 내부 반복문을 제거하고 O(N+M)으로 최적화할 수 있습니다.
- • 시간복잡도 O(N×M)
- • 중첩 반복문의 성능 문제
- • 해시맵을 통한 최적화 가능
대용량 데이터 조인이나 매칭 작업에서 중첩 반복문 대신 해시 테이블을 사용해 성능을 개선합니다.
해시맵을 사용하면 시간복잡도가 어떻게 개선되는지 구체적으로 설명해주세요.
Q. 사용자 ID로 사용자 정보를 빠르게 조회해야 하는 기능을 구현 중입니다. 배열을 사용했더니 사용자가 많아질수록 조회 속도가 느려졌습니다. 어떤 자료구조로 변경하면 조회 성능을 개선할 수 있나요?
키-값 쌍으로 저장하고 O(1)에 조회 가능한 자료구조를 생각해보세요.
해시맵(또는 딕셔너리, 객체)을 사용하면 조회 성능을 개선할 수 있습니다. 배열은 특정 ID를 찾기 위해 처음부터 순차 탐색해야 하므로 O(N)의 시간복잡도를 가집니다. 반면 해시맵은 키를 해시 함수로 변환해 직접 접근하므로 평균 O(1)의 조회 성능을 제공합니다. 사용자 ID를 키로, 사용자 정보를 값으로 저장하면 빠른 조회가 가능합니다.
- • 배열의 선형 탐색 O(N) 문제
- • 해시맵의 O(1) 조회 성능
- • 키-값 구조의 적절한 활용
사용자 세션 관리, 캐시 저장소, ID 기반 데이터 조회 등에서 해시맵을 활용합니다.
해시맵도 최악의 경우 O(N)이 될 수 있는데, 어떤 상황에서 그런가요?
Q. API에서 동일한 상품 정보를 반복적으로 요청하는 사용자들이 많아 서버 부하가 증가했습니다. 캐싱을 도입하려고 하는데, 어떤 데이터를 캐싱 대상으로 선택해야 하며, 캐싱 시 주의할 점은 무엇인가요?
자주 조회되고 변경이 적은 데이터의 특징을 생각해보세요.
캐싱 대상은 조회 빈도가 높고 변경 빈도가 낮은 데이터를 선택해야 합니다. 상품 정보처럼 자주 읽히지만 업데이트가 드문 데이터가 적합합니다. 주의할 점은 캐시 만료 시간(TTL)을 적절히 설정해 오래된 데이터가 제공되지 않도록 해야 하며, 원본 데이터가 변경될 때 캐시를 무효화(invalidation)하는 전략이 필요합니다. 또한 메모리 사용량을 고려해 캐시 크기를 제한하고 LRU 같은 교체 정책을 적용해야 합니다.
- • 읽기 빈도 높고 쓰기 빈도 낮은 데이터 선택
- • TTL과 캐시 무효화 전략
- • 메모리 관리와 교체 정책
상품 상세 정보, 카테고리 목록, 설정 정보 등 자주 조회되는 데이터를 캐싱해 DB 부하를 줄입니다.
LRU 캐시 교체 정책이 어떻게 동작하는지 설명해주세요.
Q. 10만 개의 숫자 배열에서 중복을 제거하는 기능을 구현했는데, 메모리 사용량이 너무 많다는 피드백을 받았습니다. 중복 제거 시 공간복잡도를 어떻게 고려해야 하며, 어떤 방법으로 개선할 수 있나요?
추가 자료구조 사용과 원본 배열 정렬 방식의 공간 사용 차이를 비교해보세요.
중복 제거 시 Set 자료구조를 사용하면 O(N)의 추가 공간이 필요합니다. 공간복잡도를 줄이려면 원본 배열을 정렬한 후 인접한 중복 요소를 제거하는 방식을 사용할 수 있습니다. 정렬은 O(1) 추가 공간으로 가능하며(in-place 정렬), 중복 제거도 투 포인터 기법으로 O(1) 공간에서 처리할 수 있습니다. 다만 시간복잡도는 O(N log N)으로 증가하므로 시간과 공간의 트레이드오프를 고려해야 합니다.
- • Set 사용 시 O(N) 추가 공간
- • 정렬 후 제거 방식으로 O(1) 공간
- • 시간과 공간의 트레이드오프
대용량 데이터 처리 시 메모리 제약이 있을 때 공간 효율적인 알고리즘을 선택합니다.
만약 원본 배열의 순서를 유지해야 한다면 어떤 방법을 사용하시겠습니까?
Q. 정렬된 두 배열을 합치는 기능을 구현했는데, 각 배열을 합친 후 다시 정렬하는 방식으로 작성했습니다. 이미 정렬된 배열이라는 특성을 활용해 성능을 개선할 수 있는 방법이 있나요?
두 정렬된 배열의 앞부분부터 비교하며 합치는 방법을 생각해보세요.
병합 정렬의 병합 과정을 활용하면 O(N+M)의 선형 시간에 합칠 수 있습니다. 두 배열의 시작 지점에 포인터를 두고, 각 원소를 비교하며 작은 값을 결과 배열에 추가하는 방식입니다. 현재 방식은 합친 후 정렬하므로 O((N+M) log(N+M))의 시간이 걸리지만, 투 포인터 방식은 각 원소를 한 번씩만 확인하므로 훨씬 효율적입니다. 이미 정렬된 상태라는 특성을 활용하는 것이 핵심입니다.
- • 병합 정렬의 병합 과정 활용
- • 투 포인터로 O(N+M) 달성
- • 정렬된 특성 활용
정렬된 로그 파일 병합, 시계열 데이터 통합 등에서 효율적인 병합 알고리즘을 사용합니다.
이 투 포인터 방식의 공간복잡도는 얼마인가요?
Q. 게시글 목록 API가 있는데, 사용자가 페이지를 넘길 때마다 전체 게시글을 조회한 후 필요한 부분만 잘라서 반환하고 있습니다. 게시글이 10만 건으로 늘어나자 응답 속도가 매우 느려졌습니다. 어떻게 개선할 수 있나요?
필요한 데이터만 조회하는 페이지네이션 기법을 생각해보세요.
OFFSET과 LIMIT을 사용한 페이지네이션으로 필요한 데이터만 조회해야 합니다. 전체 데이터를 조회하는 것은 불필요한 메모리와 네트워크 비용을 발생시킵니다. 예를 들어 20개씩 보여준다면 LIMIT 20, OFFSET 페이지번호×20으로 해당 페이지 데이터만 가져옵니다. 더 나아가 커서 기반 페이지네이션을 사용하면 OFFSET의 성능 문제도 해결할 수 있습니다. 인덱스가 제대로 설정되어 있어야 빠른 조회가 가능합니다.
- • LIMIT/OFFSET 페이지네이션
- • 필요한 데이터만 조회
- • 커서 기반 페이지네이션 고려
게시판, 상품 목록, 검색 결과 등 대량 데이터를 페이지 단위로 제공할 때 페이지네이션을 적용합니다.
OFFSET이 큰 값일 때 성능이 저하되는 이유와 커서 기반 페이지네이션의 장점을 설명해주세요.
Q. 특정 기능이 느리다는 사용자 불만이 있어 성능을 개선하려고 합니다. 어디가 병목인지 모르는 상황에서 성능 문제를 진단하고 개선하는 과정을 단계별로 설명해주세요.
측정 → 분석 → 개선 → 검증의 순서로 접근해보세요.
먼저 프로파일링 도구나 로깅으로 각 구간의 실행 시간을 측정해 병목 지점을 파악합니다. 데이터베이스 쿼리, 반복문, 외부 API 호출 등 시간이 오래 걸리는 부분을 찾습니다. 병목을 발견하면 해당 부분의 시간복잡도와 공간복잡도를 분석하고, 알고리즘 변경, 자료구조 교체, 캐싱 도입 등의 개선 방안을 적용합니다. 개선 후에는 다시 측정해 실제로 성능이 향상되었는지 검증하고, 새로운 병목이 없는지 확인합니다. 추측이 아닌 측정 기반으로 접근하는 것이 핵심입니다.
- • 측정을 통한 병목 파악
- • 시간복잡도 분석과 개선
- • 측정 기반 접근과 검증
실제 서비스에서 성능 이슈 발생 시 APM 도구나 프로파일러로 병목을 찾아 최적화합니다.
프로파일링 도구로 어떤 것들을 사용해보셨거나 알고 계신가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!