data-structures

3 개의 포스트

kakao

2026 카카오그룹 신입크루 공채 코딩테스트 1차 문제해설 (새 탭에서 열림)

2026 카카오그룹 신입크루 1차 코딩테스트는 문자열 처리, 시뮬레이션, 트리 최적화, 그래프 탐색 등 다양한 난도의 7문제로 구성되었으며, 글에서는 그중 일부 문제의 해결 전략을 설명합니다. 핵심은 문제별 제약을 활용해 중복 제거, 주기 탐색, 구조적 정렬, 상태 완전탐색, BFS 시뮬레이션으로 풀이 범위를 줄이는 것입니다. 특히 3번 문제는 최적해의 트리 구조를 증명해 탐색 공간을 크게 축소합니다. ## 문제 1: 스포 방지 구간의 중요한 단어 판별 - 문자열을 공백 기준으로 나누고 각 단어의 시작·끝 인덱스를 구합니다. - 단어 구간과 스포 방지 구간 `[s, e]`가 한 글자라도 겹치면 스포 방지 단어로 분류합니다. - 비스포 구간에 등장한 단어는 `Set`이나 `HashMap`에 저장해 중복 여부를 관리합니다. - 스포 방지 단어 중 다음 조건을 모두 만족하는 단어만 중요한 단어로 셉니다. - 스포 방지 구간과 겹친다. - 비스포 구간에는 등장하지 않았다. - 같은 시점에 왼쪽에서 먼저 공개된 중요한 단어와 중복되지 않는다. - 여러 단어가 동시에 공개될 때는 왼쪽 단어부터 처리하므로, 처리한 중요한 단어도 별도로 저장해야 합니다. ## 문제 2: 모든 신호등이 노란불이 되는 시점 찾기 - 각 신호등은 `G + R + Y` 길이의 주기를 무한히 반복합니다. - 모든 신호등이 동시에 노란불인 첫 시점을 찾기 위해 시뮬레이션합니다. - 정답이 존재하지 않을 수도 있으므로 종료 시점을 정해야 합니다. - 모든 주기 길이의 최소공배수까지 확인하면 이후 상태가 반복됩니다. - 각 `G + R + Y`가 최대 20이므로 충분히 큰 상한까지 직접 시뮬레이션하는 방법도 가능합니다. - 구현 방법은 여러 가지입니다. - 매초 각 신호등의 현재 상태를 갱신합니다. - 시간 배열을 만들고 각 시점의 노란불 개수를 셉니다. - 각 신호등의 노란불 구간을 수식으로 계산해 특정 시점에 노란불인지 판정합니다. - 모든 신호등의 노란불 개수가 신호등 수와 같아지는 첫 시점을 답으로 선택합니다. ## 문제 3: 트리의 리프 노드 수 최대화 - 분배수는 2 또는 3이며, 같은 깊이의 분배 노드는 모두 같은 분배수를 사용합니다. - 분배수 `k`인 노드 하나는 예산을 1 사용하고 리프 수를 `k - 1`만큼 증가시킵니다. - 루트에서 리프까지의 분배도는 경로상의 분배수 곱이며, 항상 `2^p × 3^q` 형태입니다. - 각 경로의 곱이 `split_limit`을 넘지 않아야 합니다. ### 부분 분배의 정렬 - 같은 분배수를 사용하는 연속된 층에서 부분 분배가 여러 번 발생한다면, 얕은 층부터 최대한 완전 분배하도록 순서를 바꿀 수 있습니다. - 순서를 바꿔도 다음 값은 변하지 않습니다. - 전체 예산 사용량 - 전체 리프 수 증가량 - 각 경로에서 분배수 곱의 총량 - 따라서 하나의 분배수 블록에서는 부분 분배가 최대 한 깊이에서만 발생하도록 정렬할 수 있습니다. ### 2분배층을 3분배층보다 위에 배치 - 프런티어 크기가 `W`일 때: - `2 → 3` 순서의 예산은 `W + 2W = 3W` - `3 → 2` 순서의 예산은 `W + 3W = 4W` - 두 순서 모두 최종 프런티어 크기는 `6W`지만, `2 → 3`이 더 적은 예산을 사용합니다. - 따라서 최적해는 일반적으로 다음 형태로 정렬할 수 있습니다. ```text 2분배층 여러 개 → 3분배층 여러 개 ``` ### 풀이 절차 - 가능한 모든 `(i, j)`에 대해 `2^i × 3^j ≤ split_limit`인지 확인합니다. - 각 조합마다 `2`를 사용하는 층을 먼저, `3`을 사용하는 층을 나중에 배치합니다. - 각 층에서 프런티어 전체를 분배할 수 있으면 예산을 사용해 다음 층으로 이동합니다. - 예산이 부족해지면 남은 예산만큼 부분 분배하고 해당 경우를 종료합니다. - 모든 조합 중 최종 리프 수가 가장 큰 값을 답으로 선택합니다. ## 문제 4: 바이러스 파이프 감염 최대화 - 트리의 간선은 A, B, C 세 종류의 파이프로 구성됩니다. - 한 번에는 한 종류의 파이프만 열 수 있으며, 현재 감염된 배양체에서 해당 종류의 파이프만 따라가며 연결된 모든 배양체가 감염됩니다. - 이미 감염된 배양체는 계속 감염 상태로 유지됩니다. - 같은 종류의 파이프를 연속해서 여는 것은 상태 변화가 없으므로 고려할 필요가 없습니다. - 파이프를 열 때마다 현재 감염 집합을 시작점으로 DFS 또는 BFS를 수행합니다. - 가능한 파이프 열림 순서를 모두 시뮬레이션합니다. - 최대 길이가 10이므로 순서의 수는 `3^10 = 59,049`로 충분히 작습니다. - 각 순서에서 최종 감염 배양체 수를 계산하고 최댓값을 구합니다. ## 문제 5: 카카오 앱 밀기 시뮬레이션 - 격자 안의 정사각형 앱을 한 칸 밀면, 앞을 막는 앱들도 같은 방향으로 연쇄 이동합니다. - 앱이 격자 밖으로 나가면 반대편으로 넘어오며, 이 과정에서 추가 충돌이 발생할 수 있습니다. - 앱 블록이 2×2, 3×3처럼 크기 때문에 연쇄 이동이 여러 행과 열로 퍼질 수 있습니다. ### BFS 기반 연쇄 처리 - 명령을 처리할 때 처음 선택한 앱을 시드로 둡니다. - BFS로 해당 앱이 이동할 때 함께 밀려야 하는 앱을 탐색합니다. - 탐색이 끝나면 관련 앱을 동시에 한 칸 이동시킵니다. - 격자 밖으로 잘린 앱이 생기면 이를 다음 라운드의 새로운 시드로 사용합니다. - 새로운 시드가 더 이상 없을 때까지 다음 과정을 반복합니다. 1. 시드 설정 2. BFS로 충돌 앱 탐색 3. 앱 동시 이동 4. 잘린 앱을 다음 시드로 등록 - 격자 크기와 블록 수의 제한이 작아 직접 상태를 시뮬레이션할 수 있으며, 유한한 상태 공간 때문에 연쇄 과정의 종료도 보장됩니다. 문제별로 자료구조와 알고리즘을 복잡하게 적용하기보다, 문자열 중복 관리에는 집합, 반복 주기에는 최소공배수, 트리에는 교환 논증과 완전탐색, 감염·충돌에는 BFS를 적용하는 것이 핵심입니다. 특히 최적화 문제에서는 가능한 구조를 먼저 증명해 탐색 범위를 줄이는 접근이 효과적입니다.

datadog

Go 1.24의 Swiss (새 탭에서 열림)

Datadog이 Gartner의 2026년 Observability Platforms 매직 쿼드런트에서 ‘Leader’로 선정되었다는 소식을 알리는 글입니다. 제공된 내용은 선정 사실과 Datadog의 제품·플랫폼 영역을 소개하는 내비게이션 중심이며, 평가 기준이나 구체적인 비교 분석은 포함되어 있지 않습니다. ### Gartner 매직 쿼드런트 리더 선정 - Datadog은 Gartner® Magic Quadrant™ for Observability Platforms 2026에서 Leader로 소개되었습니다. - 관련 Gartner 보고서 및 Datadog 발표 페이지로 연결되는 링크가 제공됩니다. - 본문에는 Gartner의 평가 근거, 경쟁사 비교, 점수 또는 세부 순위는 제시되지 않았습니다. ### 인프라 및 애플리케이션 모니터링 - 인프라 모니터링, 메트릭, 컨테이너와 Kubernetes 모니터링을 제공합니다. - 네트워크, 서버리스, GPU, 스토리지 및 클라우드 비용 관리 기능을 포함합니다. - 애플리케이션 성능 모니터링(APM), 서비스 모니터링, 지속적 프로파일링, 동적 계측도 지원합니다. ### 로그·데이터 관측성 - 로그 관리, 민감 데이터 스캐닝, 감사 추적, Observability Pipelines를 제공합니다. - 데이터베이스, 데이터 스트림, 데이터 품질, 데이터 작업(Job) 모니터링 기능을 포함합니다. - 수집된 로그와 데이터를 처리·필터링하고 보안 및 운영 분석에 활용할 수 있도록 구성되어 있습니다. ### 보안과 디지털 경험 - 코드 보안, SAST·IAST, 소프트웨어 구성 분석, IaC 및 클라우드 보안 기능을 제공합니다. - Cloud SIEM, 워크로드 보호, 애플리케이션·API 보호, 취약점 관리도 제품 범위에 포함됩니다. - 브라우저·모바일 RUM, 세션 리플레이, 신디틱 모니터링, 오류 추적, 제품 분석을 통해 사용자 경험을 관찰합니다. ### 소프트웨어 제공과 서비스 관리 - CI Visibility, 테스트 최적화, 지속적 테스트, 코드 커버리지, 기능 플래그를 제공합니다. - 내부 개발자 포털과 IDE 플러그인 등 개발자 생산성 기능도 포함합니다. - 이벤트 관리, 서비스 카탈로그, SLO, 인시던트 대응, 워크플로 자동화 기능으로 운영 프로세스를 지원합니다. ### AI 기반 관측성 - Bits AI Agents, Bits Chat, Bits Investigation 등 AI 기반 분석·조사 기능을 제공합니다. - AI 에이전트 관측성, GPU 모니터링, MCP Server 및 에이전트 디렉터리도 제품군에 포함됩니다. - 이러한 기능은 모니터링 데이터를 바탕으로 문제 탐색과 운영 자동화를 지원하는 방향으로 구성되어 있습니다. 실제로 Datadog 도입을 검토한다면 ‘Leader’라는 선정 결과만으로 판단하기보다, 필요한 로그·메트릭·트레이스 범위, 데이터 보존 비용, 기존 클라우드와의 통합성, 보안 및 AI 기능의 실제 운영 효과를 별도로 검증하는 것이 좋습니다.

figma

Rust의 메모리 최적화 (새 탭에서 열림)

Figma는 실시간 협업 파일의 서버 측 로딩 성능과 메모리 사용량을 개선하기 위해 Rust 자료구조를 최적화했다. 특히 노드 속성을 저장하던 `BTreeMap`을 작고 정렬된 벡터로 바꾸어 대용량 파일의 메모리 사용량을 약 25% 줄이고 역직렬화 속도도 높였다. 또한 포인터의 사용되지 않는 상위 비트에 필드 ID를 저장하는 비트 패킹 방식도 검토했지만, 이는 아직 프로덕션에 적용되지 않았다. ## 파일 로딩과 메모리 사용량의 문제 - Figma의 멀티플레이어 시스템은 파일 로딩, 협업자 업데이트 전파, 파일 상태 스냅샷 저장을 담당한다. - 복잡한 노드 그래프를 실시간으로 처리하기 위해 파일의 상당 부분을 메모리에 올린다. - 동적 페이지 로딩을 도입한 뒤 서버에서 디코딩해야 하는 파일 수가 약 30% 증가했다. - 이에 따라 로딩 경로에 있는 Rust 자료구조와 메모리 배치를 최적화할 필요가 생겼다. ## `BTreeMap`이 차지한 메모리 - Figma 파일은 삼각형, 프레임, 텍스트 등 다양한 노드의 집합으로 표현된다. - 각 노드는 색상, 타입, 부모 노드, 위치 같은 속성을 가진다. - 기존에는 속성을 다음과 같은 형태로 저장했다. ```rust BTreeMap<u16, pointer> ``` - `u16`은 속성 ID, 포인터는 속성 값의 위치를 의미한다. - 이 맵은 파일 로딩의 핵심 경로에 있었고, 전체 파일 메모리 사용량의 60% 이상을 차지했다. - 스키마의 속성 수는 200개 미만이며, 하나의 노드에 실제로 존재하는 속성은 평균 약 60개에 불과했다. - 속성 키가 작고 제한적이며, 대부분 특정 노드 유형에만 묶여 있다는 점에서 범용 맵이 과도하다고 판단했다. ## 정렬된 벡터로 자료구조 변경 - `BTreeMap` 대신 속성 ID와 포인터를 저장하는 정렬된 평탄 벡터를 사용했다. ```rust Vec<(u16, pointer)> ``` - 이론적인 복잡도만 보면 벡터가 불리하다. - 검색: `O(n)` - 중간 삽입: `O(n)` - 수정: 위치 탐색 비용 발생 - `BTreeMap`은 일반적으로 `O(log n)` 수준의 연산 제공 - 하지만 실제 파일 로딩에서는 벡터의 연속적인 메모리 배치가 더 유리했다. - CPU는 작은 선형 메모리 영역을 순차적으로 읽고 계산할 때 캐시 효율이 높다. - 결과적으로 역직렬화 속도가 향상됐고, 대용량 파일의 메모리 사용량은 약 25% 감소했다. - 이 사례는 Big O 복잡도만으로 실제 성능을 판단하기보다 데이터 크기와 메모리 지역성까지 고려해야 함을 보여준다. ## 포인터에 필드 ID를 함께 저장하는 비트 패킹 - 일반적인 포인터는 64비트지만, x86 시스템에서는 실제 주소 지정에 하위 48비트만 사용하는 경우가 많다. - 따라서 상위 16비트가 사용되지 않는다는 점에 착안해, 여기에 속성 필드 ID를 저장하는 방법을 검토했다. - 기존에는 속성 ID와 포인터를 별도 값으로 저장했지만, 비트 패킹 후에는 하나의 `u64`에 둘을 함께 담을 수 있다. ```rust Vec<u64> { [field_id_u16, pointer_u48], } ``` - 속성 ID가 정확히 16비트로 표현 가능하다는 점과 포인터의 남는 상위 비트가 맞아떨어졌다. - 이 방식은 메모리 접근과 데이터 구조의 크기를 더 줄일 가능성이 있다. - 다만 포인터의 상위 비트가 항상 사용 가능하다는 보장은 없으며, 하드웨어나 운영체제의 주소 체계가 바뀔 수 있다. - 따라서 해당 최적화는 조사 단계이며 아직 프로덕션에는 적용되지 않았다. 작은 데이터 집합에서는 범용 트리나 맵보다 단순한 연속 배열이 더 빠르고 효율적일 수 있다. Rust에서 성능을 최적화할 때는 이론적 복잡도뿐 아니라 실제 데이터 크기, CPU 캐시 지역성, 포인터 표현 방식, 플랫폼 호환성까지 함께 측정하고 판단하는 것이 중요하다.