아홉 명 전체의 키 합에서 제외할 두 명을 찾으면, 남은 일곱 명의 합을 100으로 만들 수 있습니다.
문제
서로 다른 아홉 난쟁이의 키가 주어집니다. 이 가운데 진짜 일곱 난쟁이의 키 합은 100입니다. 조건을 만족하는 일곱 명을 찾아 입력된 순서를 유지한 채 출력해야 합니다.
- 입력은 아홉 개의 줄에 걸쳐 주어지며, 각 키는 100 이하의 자연수입니다.
- 아홉 키는 모두 서로 다릅니다.
- 가능한 답이 여러 개라면 그중 하나를 출력해도 됩니다.
- 출력은 선택된 일곱 난쟁이의 키를 입력 순서대로 한 줄에 하나씩 표시합니다.
20 7 23 19 10 15 25 8 13
출력 예제 1
20 7 23 19 10 8 13
원문 자료에는 한국정보올림피아드 출처가 표시되어 있으며, 별도의 문제 URL은 제공되지 않았습니다.
풀이와 정답
풀이와 정답 보기 (클릭)
일곱 명을 직접 고르면 아홉 명 중 일곱 명의 모든 조합을 생각해야 합니다. 반대로 정답에서 빠질 두 명을 고르면 확인해야 할 대상이 단순해집니다. 전체 키의 합을 구한 뒤 두 키를 빼서 100이 되는지만 검사하면 됩니다.
두 후보는 서로 다른 인덱스로 선택해야 하므로 바깥 반복문의 다음 위치부터 안쪽 반복문을 시작합니다. 이 방식은 같은 사람을 두 번 고르지 않으며, 순서만 바뀐 동일한 쌍도 다시 검사하지 않습니다.
조건을 만족한 두 원소를 배열에서 제거할 때는 큰 인덱스를 먼저 삭제해야 합니다. 앞쪽 원소부터 지우면 뒤쪽 원소의 위치가 하나 당겨져 원하지 않는 값이 삭제될 수 있기 때문입니다.
전체 합을 T라고 하면 제외할 두 키의 합은 T - 100이어야 합니다. 이 등식으로 목표를 바꾸면, 일곱 원소의 조합을 직접 구성하지 않고 두 원소의 쌍만 확인할 수 있습니다. 아홉 명 중 두 명을 고르는 쌍은 최대 36개뿐이므로 별도의 최적화 자료구조가 필요하지 않습니다.
입력 순서를 유지해야 하므로 정렬은 사용하지 않습니다. 정렬한 뒤 일곱 값을 출력하면 합은 맞더라도 원문이 요구한 순서가 달라질 수 있습니다. 처음 배열의 순서를 보존한 복사본에서 두 원소만 제거하면 나머지 원소의 상대적 순서가 그대로 남습니다.
키는 모두 서로 다르지만, 탐색은 값이 아니라 인덱스를 기준으로 진행합니다. first와 second가 서로 다른 위치를 가리키고, 안쪽 반복이 항상 first + 1에서 시작하므로 자기 자신을 선택하거나 같은 쌍을 반대 순서로 다시 확인하지 않습니다.
알고리즘 설계

- 아홉 키의 전체 합을 계산합니다.
- 이중 반복문으로 제외할 두 인덱스
i와j를 선택합니다. 전체 합 - heights[i] - heights[j]가 100인지 확인합니다.- 조건이 맞으면 뒤쪽 인덱스
j, 앞쪽 인덱스i순서로 제거하고 탐색을 끝냅니다. - 남은 일곱 값을 원래 입력 순서대로 출력합니다.
정답 일곱 명의 합이 100이라면 제외되는 두 명의 합은 반드시 전체 합에서 100을 뺀 값과 같습니다. 따라서 가능한 두 인덱스 쌍을 빠짐없이 확인하면 정답 후보를 찾을 수 있습니다. 입력 크기는 아홉 개로 고정되어 있어 모든 쌍을 확인해도 충분히 빠릅니다.
정확성은 완전성과 보존성으로 나누어 확인할 수 있습니다. 완전성 측면에서 이중 반복문은 first < second인 모든 두 인덱스 조합을 한 번씩 검사합니다. 문제 조건상 답이 존재한다면 제외해야 할 두 인덱스도 이 목록에 반드시 포함됩니다.
보존성 측면에서는 조건을 만족하기 전까지 배열을 수정하지 않습니다. 정답 쌍을 찾은 뒤에만 두 원소를 제거하며, 큰 인덱스를 먼저 지워 작은 인덱스의 위치가 달라지지 않게 합니다. 제거되지 않은 일곱 원소는 처음 배열에서의 상대적 순서를 그대로 유지합니다.
가능한 답이 여러 개라면 가장 먼저 발견한 쌍에서 탐색을 끝냅니다. 원문은 가능한 답 중 하나를 허용하므로 모든 정답 쌍을 수집할 필요가 없습니다. 이 조기 종료는 출력의 유효성을 바꾸지 않으면서 불필요한 반복만 줄입니다.
JavaScript 풀이

제공된 코드의 핵심 접근은 정확합니다. 다만 answer = arr는 같은 배열을 가리켜 원본까지 변경하고, ==는 형 변환을 허용합니다. 아래 정답 코드는 배열을 복사해 입력값을 보존하고, 엄격한 비교 연산자 ===를 사용합니다. 또한 상태 변수 대신 레이블이 있는 break로 두 반복문을 한 번에 종료합니다.
const fs = require('fs');
const heights = fs
.readFileSync(0, 'utf8')
.trim()
.split(/\s+/)
.map(Number);
function findSevenDwarfs(inputHeights) {
const result = [...inputHeights];
const totalHeight = result.reduce(
(sum, height) => sum + height,
0
);
search:
for (let first = 0; first < result.length - 1; first++) {
for (let second = first + 1; second < result.length; second++) {
if (totalHeight - result[first] - result[second] === 100) {
result.splice(second, 1);
result.splice(first, 1);
break search;
}
}
}
return result;
}
console.log(findSevenDwarfs(heights).join('\n'));
split(/\s+/)는 줄바꿈과 공백을 모두 구분자로 처리하므로 아홉 줄 입력을 숫자 배열로 바꿉니다. result는 입력 배열의 복사본이어서 삭제 이후에도 원본 inputHeights는 유지됩니다. 삭제 전에는 항상 second가 first보다 크므로 뒤쪽 원소를 먼저 지우는 순서도 보장됩니다.
정답 쌍을 찾은 뒤에는 더 탐색할 필요가 없습니다. 레이블 search에 대한 break가 두 반복문을 모두 끝내고, 일곱 개만 남은 배열을 그대로 반환합니다. 정렬을 하지 않으므로 결과의 상대적인 순서는 입력과 같습니다.
복잡도와 검증
전체 합 계산은 O(n), 두 후보를 찾는 이중 반복문은 O(n²)입니다. 따라서 전체 시간 복잡도는 O(n²)입니다. 정답 코드가 입력 배열을 복사하므로 추가 공간 복잡도는 O(n)입니다. 이 문제에서는 n = 9로 고정되어 제한 안에서 여유롭게 실행됩니다.
공식 예제의 전체 합은 140이며, 15와 25를 제외하면 남은 합이 100입니다. 코드는 두 값을 뒤쪽 인덱스부터 제거하므로 20, 7, 23, 19, 10, 8, 13의 입력 순서를 유지합니다. 모든 키가 서로 다르다는 조건 덕분에 값이 아니라 인덱스로 두 후보를 관리해도 혼동이 없습니다.
예제 탐색에서는 각 쌍을 순서대로 확인하다가 15와 25를 만났을 때 조건식이 참이 됩니다. 두 원소를 제거하면 배열 길이는 아홉에서 정확히 일곱 개로 줄고, 삭제 대상보다 앞이나 사이에 있던 원소는 값이 바뀌지 않습니다. 따라서 합 조건과 출력 개수, 입력 순서를 한 번에 만족합니다.
최댓값이 100인 입력도 별도 처리가 필요하지 않습니다. 아홉 키의 전체 합은 최대 900이므로 모든 계산은 JavaScript의 안전한 정수 범위보다 매우 작습니다. 덧셈과 뺄셈만 사용하므로 부동소수점 오차를 고려할 상황도 없습니다.
서로 다른 키라는 조건은 같은 숫자를 구분하는 추가 장치를 만들지 않아도 된다는 뜻입니다. 그러나 정답 코드는 값 검색이 아니라 인덱스 쌍을 사용하므로, 탐색 과정 자체는 각 위치를 명확하게 구분합니다. 삭제할 위치가 결정된 뒤에만 배열을 바꾸기 때문에 아직 검사하지 않은 후보가 중간에 이동하는 문제도 생기지 않습니다.
배열을 수정하지 않고 filter로 두 인덱스를 제외한 새 배열을 만드는 방법도 가능합니다. 이번 코드는 제공된 시도의 splice 접근을 살리면서 원본 훼손만 막기 위해 먼저 복사본을 만들었습니다. 원래 시도의 핵심을 유지하고 부작용을 줄인 수정 결과라는 점이 구현 선택의 기준입니다.
경계 조건에서도 각 키는 100 이하의 자연수이므로 JavaScript의 일반 정수 연산 범위에 충분히 들어갑니다. 가능한 답이 여러 개인 경우에는 첫 번째로 찾은 쌍을 사용하며, 문제 조건에서 허용하는 출력 방식과 일치합니다.
마지막으로 출력 단계는 계산 과정의 중간값이나 제외된 두 키를 표시하지 않습니다. 정답 배열의 일곱 값만 줄 단위로 연결하므로 문제에서 요구한 출력 형식에 정확히 대응합니다. 탐색, 삭제, 출력의 역할이 분리되어 있어 각 단계도 독립적으로 확인할 수 있습니다.
같이 읽으면 좋은 글
풀이 전에 확인할 순서
- 입력값과 출력값을 한 문장으로 다시 적습니다.
- 반복할 대상과 비교·저장할 값을 정합니다.
- 필요한 자료구조와 시간복잡도를 예상합니다.
- 코드를 보기 전에 손으로 작은 예제를 계산합니다.
힌트: 일곱 난쟁이 JavaScript 풀이: 두 명을 제외하는 완전탐색
정답 코드를 바로 따라 쓰기보다, 본문에서 값이 갱신되는 조건과 반복 범위를 먼저 찾으세요. 반복 한 번마다 반드시 유지되어야 하는 값이 무엇인지 적으면 풀이의 중심 변수를 고르기 쉽습니다.
테스트 확인
- 가능한 가장 작은 입력
- 같은 값이나 문자가 반복되는 입력
- 정답이 처음 또는 마지막 위치에서 결정되는 입력
- 입력 제한에 가까운 경우의 실행 시간
확인 결과: 본문의 예제뿐 아니라 위 경계 사례에서도 예상값과 실제 출력이 같아야 풀이가 완료됩니다.
이 글이 도움이 되었나요?
코딩테스트 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의 새 글을 확인할 수 있습니다.