[창작 문제] 이동 실험실의 연결 일지
장치 연결 요청마다 남은 네트워크 수와 요청 첫 장치의 네트워크 크기를 기록합니다. 중복 요청과 자기 연결은 새로운 합병이 아닙니다.

이 문제는 BlogFlow 자료구조 학습용으로 독립 창작했습니다. 외부 문제의 지문이나 테스트를 옮기지 않았습니다.
문제
이동 실험실은 n개의 장치를 처음에는 서로 분리해 둡니다. 관리자가 links의 순서대로 두 장치를 연결합니다. 각 요청을 처리한 직후 [전체 연결 성분 수, 요청 첫 장치가 속한 성분의 크기]를 일지에 남기세요. 이미 연결된 두 장치를 다시 연결하거나 같은 장치를 양쪽에 적은 요청도 일지 한 줄은 남겨야 합니다.
관련 구현 설명: JavaScript Union-Find: 경로 압축과 크기 합치기로 연결 상태 관리하기
입력·출력과 제약
JSON 객체 {n, links}를 표준 입력으로 받습니다. links의 각 원소 [a,b]는 두 장치 번호입니다.
요청 순서대로 두 정수를 담은 배열을 모아 JSON 배열 하나로 출력합니다. links가 비면 []입니다.
0 ≤ n ≤ 100,000, 0 ≤ links.length ≤ 100,000. 모든 번호는 정수이며 0 ≤ a,b < n입니다. n=0이면 links는 빈 배열입니다.
입력은 위 계약을 만족한다고 가정합니다. 온라인 채점기는 제공하지 않으며 로컬 Node.js에서 JSON 입력으로 실행합니다.
예시
예시 1 입력:
{"n":5,"links":[[0,1],[2,3],[1,2],[0,3],[4,4]]}
예시 1 출력:
[[4,2],[3,2],[2,4],[2,4],[2,1]]
예시 2 입력:
{"n":0,"links":[]}
예시 2 출력:
[]
힌트
성공한 합병 횟수만 전체 성분 수에서 빼세요. 성분 크기는 요청한 원소의 현재 대표를 통해 읽습니다.
정답과 해설
정답 코드와 해설 펼치기
Node.js 24 CommonJS용 전체 풀이입니다. union-find-problem.cjs로 저장하세요. 클래스 선언, solve 함수, 표준 입력 처리가 모두 들어 있어 가이드 파일을 별도로 가져오지 않습니다. 예시 입력을 input.json에 저장하고 터미널에서 실행합니다.
Windows PowerShell:
Get-Content -Raw -Encoding UTF8 .input.json | node .union-find-problem.cjs
macOS / Linux:
node union-find-problem.cjs < input.json
class UnionFind {
constructor(n) {
if (!Number.isInteger(n) || n < 0 || n > 1_000_000) {
throw new RangeError('n은 0~1,000,000 정수여야 합니다.');
}
this.parent = Array.from({ length: n }, (_, i) => i);
this.sizes = Array(n).fill(1);
this.count = n;
}
check(x) {
if (!Number.isInteger(x) || x < 0 || x >= this.parent.length) {
throw new RangeError('원소 번호가 범위를 벗어났습니다.');
}
}
find(x) {
this.check(x);
let root = x;
while (this.parent[root] !== root) root = this.parent[root];
while (this.parent[x] !== x) {
const next = this.parent[x];
this.parent[x] = root;
x = next;
}
return root;
}
union(a, b) {
let ra = this.find(a), rb = this.find(b);
if (ra === rb) return false;
if (this.sizes[ra] < this.sizes[rb]) [ra, rb] = [rb, ra];
this.parent[rb] = ra;
this.sizes[ra] += this.sizes[rb];
this.count--;
return true;
}
same(a, b) { return this.find(a) === this.find(b); }
sizeOf(x) { return this.sizes[this.find(x)]; }
}
function solve({ n, links }) {
const d = new UnionFind(n);
return links.map(([a, b]) => {
d.union(a, b);
return [d.count, d.sizeOf(a)];
});
}
module.exports = { solve };
if (require.main === module) {
const input = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
console.log(JSON.stringify(solve(input)));
}
links.map의 각 순회가 일지 한 줄에 대응합니다. union이 false여도 sizeOf(a)는 계산해야 합니다. 처음 두 요청으로 크기 2인 성분 두 개가 생기고 세 번째 요청으로 크기 4가 됩니다. 네 번째는 같은 성분 안의 중복 요청이므로 [2,4], 다섯 번째는 혼자 남은 장치 4의 자기 연결이므로 [2,1]입니다.
parent가 만드는 구조는 여러 개의 뿌리 있는 나무입니다. 루트만 parent[root]===root이고, 나머지는 같은 성분 안의 조상을 가리킵니다. 루트에서만 sizes[root]가 정확한 성분 크기입니다. 합쳐진 옛 루트의 sizes는 남아 있어도 더 이상 의미가 없으므로 sizeOf는 반드시 find를 먼저 호출합니다.
크기 합치기는 작은 나무의 루트를 큰 나무의 루트 아래에 붙입니다. 어떤 원소의 깊이가 1 증가했다면 그 원소가 속한 성분의 크기는 적어도 2배가 됩니다. 크기는 n을 넘지 않으므로 깊이는 O(log n)입니다. 합치기를 원소 a,b에 직접 적용하지 않고 대표 ra,rb에 적용해야 성분 일부만 떼어 붙이는 실수를 피할 수 있습니다.
초기화 O(n), q개 요청의 총 시간 O(n+qα(n)) 상환, 구조 O(n)와 반환 일지 O(q) 공간입니다. 개별 요청의 최악은 O(log n)입니다.
표본과 경계를 직접 확인하려면 다음 코드를 union-find-check.cjs로 저장하고 같은 폴더에서 node union-find-check.cjs를 실행하세요. assert가 맞으면 출력 없이 종료하고, 다르면 예외와 함께 실패합니다.
const assert = require('node:assert/strict');
const { solve } = require('./union-find-problem.cjs');
assert.deepEqual(
solve({
"n": 5,
"links": [
[
0,
1
],
[
2,
3
],
[
1,
2
],
[
0,
3
],
[
4,
4
]
]
}),
[[4,2],[3,2],[2,4],[2,4],[2,1]],
);
assert.deepEqual(
solve({
"n": 0,
"links": []
}),
[],
);
연결 학습과 공식 자료
JavaScript Union-Find: 경로 압축과 크기 합치기로 연결 상태 관리하기에서 연산별 이유와 전체 복잡도를 이어서 확인할 수 있습니다. 다른 형식의 공식 연습은 AtCoder A – Disjoint Set Union를 참고하세요. 외부 문제의 정답이나 지문은 이 페이지에 복제하지 않았습니다.
공식 자료 확인일: 2026년 9월 10일. 구현은 이 글의 JavaScript 계약에 맞춰 독립적으로 작성했습니다. 다른 언어 라이브러리의 API와 숫자 범위가 그대로 적용되는 것은 아닙니다.
풀이 전에 확인할 순서
- 입력값과 출력값을 한 문장으로 다시 적습니다.
- 반복할 대상과 비교·저장할 값을 정합니다.
- 필요한 자료구조와 시간복잡도를 예상합니다.
- 코드를 보기 전에 손으로 작은 예제를 계산합니다.
힌트: 코딩테스트 JS Union-Find: 연결 성분 수와 크기 구하기
정답 코드를 바로 따라 쓰기보다, 본문에서 값이 갱신되는 조건과 반복 범위를 먼저 찾으세요. 반복 한 번마다 반드시 유지되어야 하는 값이 무엇인지 적으면 풀이의 중심 변수를 고르기 쉽습니다.
테스트 확인
- 가능한 가장 작은 입력
- 같은 값이나 문자가 반복되는 입력
- 정답이 처음 또는 마지막 위치에서 결정되는 입력
- 입력 제한에 가까운 경우의 실행 시간
확인 결과: 본문의 예제뿐 아니라 위 경계 사례에서도 예상값과 실제 출력이 같아야 풀이가 완료됩니다.
이 글이 도움이 되었나요?
코딩테스트 JavaScript 학습 순서
필수 49개 · 전체 49개
읽음 기록 관리
전체 과정 목차 (49개)
- 필수 길잡이 · 코딩테스트 JS 자료구조 로드맵: 배열, 해시, 스택, 투 포인터 순서
- 필수 학습 · 세 수 중 최솟값 JavaScript 조건문 풀이 정리
- 필수 학습 · 삼각형 판별하기 JavaScript 풀이
- 필수 학습 · 연필 개수 JavaScript 풀이
- 필수 학습 · 1부터 N까지 합 출력하기 JavaScript 풀이
- 필수 학습 · 최솟값 구하기 JavaScript 풀이|배열 순회와 비교 갱신 원리
- 필수 학습 · 홀수 JavaScript 풀이: 조건 판별과 결과 처리 정리
- 필수 학습 · 10부제 JavaScript 풀이: 끝자리 비교로 위반 차량 수 세기
- 필수 학습 · A를 #으로 JavaScript 풀이: 문자열 순회와 치환
- 필수 학습 · 문자 찾기 JavaScript 풀이: 문자열 순회로 개수 세기
- 필수 학습 · 대문자 찾기 JavaScript 풀이
- 필수 학습 · 대문자로 통일 JavaScript 풀이
- 필수 학습 · 대소문자 변환 JavaScript 풀이
- 필수 학습 · 일곱 난쟁이 JavaScript 풀이: 두 명을 제외하는 완전탐색
- 필수 학습 · 코딩테스트 JS Map 풀이: 학급 회장 득표수 세기
- 필수 학습 · 코딩테스트 JS 스택 풀이: 올바른 괄호 검증하기
- 필수 학습 · 코딩테스트 JS 스택 풀이: 괄호문자 제거하기
- 필수 학습 · 코딩테스트 JS 스택 풀이: 크레인 인형뽑기 처리법
- 필수 학습 · 코딩테스트 JS 스택 풀이: 후위식 연산 계산하기
- 필수 학습 · 코딩테스트 JS 스택 풀이: 쇠막대기 레이저 절단 개수 세기
- 필수 학습 · 코딩테스트 JS 투 포인터 풀이: 두 정렬 배열 합치기
- 필수 학습 · 코딩테스트 JS 투 포인터 풀이: 공통 원소 추출하기
- 필수 학습 · 코딩테스트 JS 슬라이딩 윈도우 풀이: 최대 매출 구간 합 계산하기
- 필수 학습 · JavaScript 투 포인터: 합이 M인 연속 부분수열 개수
- 필수 학습 · 코딩테스트 JS 해시 풀이: 모든 아나그램 찾기
- 필수 학습 · 가장 긴 문자열 JavaScript 풀이
- 필수 학습 · 가운데 문자 출력 JavaScript 풀이
- 필수 학습 · 중복문자제거 JavaScript 풀이
- 필수 학습 · 코딩테스트 JS 고급: 최소 힙으로 다익스트라 최단 경로 구하기
- 필수 학습 · 코딩테스트 JS Union-Find: 연결 성분 수와 크기 구하기 현재 글
- 필수 학습 · 코딩테스트 JS Trie: 접두사에 맞는 단어 수 세기
- 필수 학습 · 코딩테스트 JS Fenwick Tree: 값 갱신과 구간 합 처리
- 필수 학습 · 코딩테스트 JS 세그먼트 트리: 단일 대입과 구간 합
- 필수 학습 · 코딩테스트 JS LRU 캐시: 지도 타일 재사용 기록
- 필수 학습 · 코딩테스트 JS AVL 트리: 기준 이상 최솟값 찾기
- 필수 학습 · 코딩테스트 JS 큐: 상담 창구 대기열 명령 처리
- 필수 학습 · 코딩테스트 JS 연결 리스트: 재생 대기 목록 관리
- 필수 학습 · JavaScript 원형 덱 연습: 최근 기록 창과 되돌리기
- 필수 학습 · JavaScript 해시 테이블 연습: 정규화 문자열 빈도와 등장 순서
- 필수 학습 · JavaScript 트리 순회 연습: 깊이별 노드 묶기
- 필수 학습 · JavaScript BST 연습: 닫힌 구간의 중복 키 보고서
- 필수 학습 · JavaScript 최소 힙 연습: 동률 순서를 지키는 작업 스케줄러
- 필수 학습 · JavaScript 그래프 연습: 연결 구역 크기를 작은 순서로 출력하기
- 필수 학습 · 중복단어제거 JavaScript 풀이
- 필수 학습 · TypeScript 이진 탐색 연습: 숫자 카드 존재 여부 확인
- 필수 학습 · 큰 수 출력하기 JavaScript 풀이
- 필수 학습 · 보이는 학생 JavaScript 풀이
- 필수 학습 · 가위바위보 JavaScript 풀이
- 필수 학습 · 점수계산 JavaScript 풀이
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.