읽기 전에 알아두면 좋아요
아래 개념이 익숙하면 본문을 바로 읽으세요. 낯선 개념만 링크에서 복습하면 됩니다.
- 완전탐색과 쌍 비교: 중복 없는 후보 열거와 순위 계산완전탐색은 가능한 후보를 빠짐없이 살펴보고 비교하는 방법입니다. 제외할 서로 다른 두 인덱스를 한 번씩 열거하고 입력 순서를 보존합니다.
- JavaScript 배열: 인덱스 조회와 삽입·삭제 비용배열은 여러 값을 순서대로 담습니다. 인덱스로 값을 읽고 반복문으로 하나씩 살펴봅니다. 인덱스 접근과 배열을 순회할 때의 연산 비용을 확인합니다.
개념과 예제는 실행하지 않아도 읽을 수 있습니다. 내 컴퓨터·터미널에서 직접 실행하는 과정은 선택 실습입니다.
과정 위치와 선택 복습 안내
과정 위치: 완전탐색과 격자 · 문제
과정 위치는 이 글이 속한 묶음입니다. 이 단계의 모든 개념을 먼저 읽을 필요는 없습니다. 위에 연결한 개념 중 낯선 내용만 복습하세요. 문제의 조건·상태·갱신 순서는 익숙한 언어로 설명하면 됩니다.
JavaScript로 문법·실행 복습하기 (선택)
개념 글의 코드는 JavaScript 예시입니다. 문제 화면에서는 JavaScript·Python·Java·C++·C# 중 익숙한 언어의 함수를 작성하세요. 본문의 Node.js 입출력 예시는 로컬 실행을 위한 별도 안내입니다.
아홉 난쟁이 중 키 합이 100인 일곱 명을 어떤 순서로 반환하나요?
아홉 명의 키에서 합이 100인 일곱 명의 키를 입력 순서대로 반환하는 문제입니다. 배열·합계·쌍 비교의 기본을 준비하고, 아래 입력·반환 계약을 확인해 직접 풀어보세요.
적용 조건·범위: 서로 다른 아홉 난쟁이의 키가 주어집니다. 이 가운데 진짜 일곱 난쟁이의 키 합은 100입니다. 조건을 만족하는 일곱 명을 찾아 입력된 순서를 유지한 채 출력해야 합니다.
공식 문서 참고: 관련 개념: MDN splice의 원본 배열 변경과 인덱스
문제
서로 다른 아홉 난쟁이의 키가 주어집니다. 이 가운데 진짜 일곱 난쟁이의 키 합은 100입니다. 조건을 만족하는 일곱 명을 찾아 입력된 순서를 유지한 채 출력해야 합니다.
- 입력은 아홉 개의 줄에 걸쳐 주어지며, 각 키는 100 이하의 자연수입니다.
- 아홉 키는 모두 서로 다릅니다.
- 가능한 답이 여러 개라면 그중 하나를 출력해도 됩니다.
- 출력은 선택된 일곱 난쟁이의 키를 입력 순서대로 한 줄에 하나씩 표시합니다.
20 7 23 19 10 15 25 8 13
출력 예제 1
20 7 23 19 10 8 13
원문 자료에는 한국정보올림피아드 출처가 표시되어 있으며, 별도의 문제 URL은 제공되지 않았습니다.
직접 풀어보기
먼저 선택한 언어의 입력·반환 계약에 맞춰 작성해 보세요. 힌트 받기와 정답과 비교하기는 코드를 실행하지 않는 AI 분석입니다. 해답·해설은 아래에서 필요할 때 펼칠 수 있습니다.
AI 힌트
코드를 실행한 채점 결과가 아닌 AI의 코드 분석입니다.
해답·해설 보기
function solution(heights) {
const total = heights.reduce((sum, h) => sum + h, 0);
for (let i = 0; i < heights.length; i++) for (let j = i + 1; j < heights.length; j++) {
if (total - heights[i] - heights[j] === 100) {
const result = heights.slice();
result.splice(j, 1);
result.splice(i, 1);
return result;
}
}
return [];
}
solution(heights)에 길이 9 정수 배열을 전달하며 합이 100인 일곱 키의 배열을 입력 순서대로 반환합니다. 입력은 문제의 유효한 범위를 만족합니다. 표준 입력·출력 없이 결과를 반환하세요.
def solution(heights):
total = sum(heights)
for i in range(len(heights)):
for j in range(i+1,len(heights)):
if total-heights[i]-heights[j] == 100:
result = heights.copy()
del result[j]
del result[i]
return result
return []
solution(heights)에 길이 9 정수 리스트를 전달하며 일곱 키의 리스트를 입력 순서대로 반환합니다. 입력은 문제의 유효한 범위를 만족합니다. 표준 입력·출력 없이 결과를 반환하세요.
import java.util.*;
class Solution {
public int[] solution(int[] heights) {
int total = 0;
for (int h : heights) total += h;
for (int i = 0; i < heights.length; i++) for (int j = i + 1; j < heights.length; j++) {
if (total - heights[i] - heights[j] == 100) {
List < Integer > result = new ArrayList < >();
for (int h : heights) result.add(h);
result.remove(j);
result.remove(i);
int[] out = new int[result.size()];
for (int k = 0; k < out.length; k++) out[k] = result.get(k);
return out;
}
}
return new int[0];
}
}
Solution.solution(int[] heights)는 일곱 키를 입력 순서대로 담은 int[]를 반환합니다. 입력은 문제의 유효한 범위를 만족합니다. 표준 입력·출력 없이 결과를 반환하세요.
#include <algorithm>
#include <array>
#include <functional>
#include <list>
#include <limits>
#include <memory>
#include <numeric>
#include <queue>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
using namespace std;
vector < int > solution(const vector < int > & heights) {
int total = accumulate(heights.begin(), heights.end(), 0);
for (size_t i = 0; i < heights.size(); i++) for (size_t j = i + 1; j < heights.size(); j++) {
if (total - heights[i] - heights[j] == 100) {
vector < int > result = heights;
result.erase(result.begin() + j);
result.erase(result.begin() + i);
return result;
}
}
return {
};
}
solution(const vector<int>& heights)는 일곱 키의 vector<int>를 입력 순서대로 반환합니다. 입력은 문제의 유효한 범위를 만족합니다. 표준 입력·출력 없이 결과를 반환하세요.
using System;
using System.Collections.Generic;
using System.Text;
public class Solution {
public int[] Solve(int[] heights) {
int total = 0;
foreach(int h in heights) total += h;
for (int i = 0; i < heights.Length; i++) for (int j = i + 1; j < heights.Length; j++) {
if (total - heights[i] - heights[j] == 100) {
var result = new List < int >(heights);
result.RemoveAt(j);
result.RemoveAt(i);
return result.ToArray();
}
}
return new int[0];
}
}
Solution.Solve(int[] heights)는 일곱 키를 입력 순서대로 담은 int[]를 반환합니다. 입력은 문제의 유효한 범위를 만족합니다. 표준 입력·출력 없이 결과를 반환하세요.
원자료와 확인 범위
2026-10-12에 제공된 학습 자료 섹션 1. 기본문제풀이.pdf의 8쪽 ‘일곱 난쟁이’와 문제 조건·예제를 대조했습니다. 같은 ZIP의 해당 문제 TXT는 풀이 코드 자료입니다. 이 자료의 최초 출제 원문·저자·공개 배포 주소까지 확인한 것은 아닙니다.
제공 PDF에는 한국정보올림피아드가 출처로 표시되어 있습니다. 이번 확인에서 KOI 공식 과거 대회 기록의 해당 옛 문제 원본을 확보하지 못했으므로 대회 연도·부문과 공식 채점 결과를 추가로 단정하지 않습니다.
이번 대조는 원자료의 문제 조건과 예제 확인입니다. 이 글의 전체 코드를 새로 실행하거나 공식 채점에 제출한 결과를 뜻하지 않습니다. 아래 예제·자가 확인 항목은 직접 실행해 기대 출력과 비교하는 기준입니다.
일곱 명을 직접 고르면 아홉 명 중 일곱 명의 모든 조합을 생각해야 합니다. 반대로 정답에서 빠질 두 명을 고르면 확인해야 할 대상이 단순해집니다. 전체 키의 합을 구한 뒤 두 키를 빼서 100이 되는지만 검사하면 됩니다.
두 후보는 서로 다른 인덱스로 선택해야 하므로 바깥 반복문의 다음 위치부터 안쪽 반복문을 시작합니다. 이 방식은 같은 사람을 두 번 고르지 않으며, 순서만 바뀐 동일한 쌍도 다시 검사하지 않습니다.
조건을 만족한 두 원소를 배열에서 제거할 때는 큰 인덱스를 먼저 삭제해야 합니다. 앞쪽 원소부터 지우면 뒤쪽 원소의 위치가 하나 당겨져 원하지 않는 값이 삭제될 수 있기 때문입니다.
전체 합을 T라고 하면 제외할 두 키의 합은 T - 100이어야 합니다. 이 등식으로 목표를 바꾸면, 일곱 원소의 조합을 직접 구성하지 않고 두 원소의 쌍만 확인할 수 있습니다. 아홉 명 중 두 명을 고르는 쌍은 최대 36개뿐이므로 별도의 최적화 자료구조가 필요하지 않습니다.
입력 순서를 유지해야 하므로 정렬은 사용하지 않습니다. 정렬한 뒤 일곱 값을 출력하면 합은 맞더라도 원문이 요구한 순서가 달라질 수 있습니다. 처음 배열의 순서를 보존한 복사본에서 두 원소만 제거하면 나머지 원소의 상대적 순서가 그대로 남습니다.
키는 모두 서로 다르지만, 탐색은 값이 아니라 인덱스를 기준으로 진행합니다. first와 second가 서로 다른 위치를 가리키고, 안쪽 반복이 항상 first + 1에서 시작하므로 자기 자신을 선택하거나 같은 쌍을 반대 순서로 다시 확인하지 않습니다.
알고리즘 설계

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

제공된 코드의 핵심 접근은 정확합니다. 다만 answer = arr는 같은 배열을 가리켜 원본까지 변경하고, ==는 형 변환을 허용합니다. 아래 정답 코드는 배열을 복사해 입력값을 보존하고, 엄격한 비교 연산자 ===를 사용합니다. 또한 상태 변수 대신 레이블이 있는 break로 두 반복문을 한 번에 종료합니다.
아래 완성 코드를 Node.js용 solution.cjs로 저장합니다. input.txt에는 예제 키 20, 7, 23, 19, 10, 15, 25, 8, 13을 한 줄에 하나씩 적습니다. 사람 수 9를 첫 줄에 추가하지 않습니다. Bash·명령 프롬프트에서는 node solution.cjs < input.txt, PowerShell에서는 cmd /c “node solution.cjs < input.txt”로 실행합니다. 기대 출력은 20, 7, 23, 19, 10, 8, 13의 일곱 줄입니다. 출력 개수·합 100·입력 상대 순서를 함께 확인하세요.
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의 입력 순서를 유지합니다. 모든 키가 서로 다르다는 조건 덕분에 값이 아니라 인덱스로 두 후보를 관리해도 혼동이 없습니다.
출력 전에는 일곱 값의 합과 개수, 입력에서의 상대 순서를 함께 확인합니다. 이 세 조건은 정답 후보를 찾는 일과 출력 형식을 맞추는 일을 구분하는 기준입니다.
최댓값이 100인 입력도 별도 처리가 필요하지 않습니다. 아홉 키의 전체 합은 최대 900이므로 모든 계산은 JavaScript의 안전한 정수 범위보다 매우 작습니다. 덧셈과 뺄셈만 사용하므로 부동소수점 오차를 고려할 상황도 없습니다.
서로 다른 키라는 조건은 같은 숫자를 구분하는 추가 장치를 만들지 않아도 된다는 뜻입니다. 그러나 정답 코드는 값 검색이 아니라 인덱스 쌍을 사용하므로, 탐색 과정 자체는 각 위치를 명확하게 구분합니다. 삭제할 위치가 결정된 뒤에만 배열을 바꾸기 때문에 아직 검사하지 않은 후보가 중간에 이동하는 문제도 생기지 않습니다.
배열을 수정하지 않고 filter로 두 인덱스를 제외한 새 배열을 만드는 방법도 가능합니다. 이번 코드는 제공된 시도의 splice 접근을 살리면서 원본 훼손만 막기 위해 먼저 복사본을 만들었습니다. 원래 시도의 핵심을 유지하고 부작용을 줄인 수정 결과라는 점이 구현 선택의 기준입니다.
경계 조건에서도 각 키는 100 이하의 자연수이므로 JavaScript의 일반 정수 연산 범위에 충분히 들어갑니다. 가능한 답이 여러 개인 경우에는 첫 번째로 찾은 쌍을 사용하며, 문제 조건에서 허용하는 출력 방식과 일치합니다.
마지막으로 출력 단계는 계산 과정의 중간값이나 제외된 두 키를 표시하지 않습니다. 정답 배열의 일곱 값만 줄 단위로 연결하므로 문제에서 요구한 출력 형식에 정확히 대응합니다. 탐색, 삭제, 출력의 역할이 분리되어 있어 각 단계도 독립적으로 확인할 수 있습니다.
이 문제를 푼 뒤 확인하기
키는 모두 다르고 정답이 존재한다는 조건을 유지하세요. 예제에서 15와 25를 제외한 일곱 값의 합이 100이고, 입력에서의 상대 순서가 유지되는지 확인하세요.
본문의 예제와 이 반례를 직접 실행해 예상 출력과 비교하고, 결과가 다르면 입력 조건과 반복 범위를 다시 확인하세요.
이 글이 도움이 되었나요?
이어서 공부하기
체크포인트: 해설을 가리고 다시 풀고, 경계 입력을 하나 바꾸어 예상 결과와 실제 결과를 비교하세요. 같은 쌍을 두 번 세지 않는 이유와 모서리·대각선의 좌표를 설명하세요.
다음 추천 · 문제: 등수구하기 풀이
권장 순서는 학습 가이드와 같습니다. 다른 순서는 접힌 참고 목록에서 확인할 수 있습니다. 읽음 표시는 숙달이나 채점 결과가 아닙니다.
원래 과정 목록 순서 (선택)
읽음 기록
읽음 — / 전체 58개 · 필수 58개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.