
난이도: ★★☆☆☆ • solved on: 2025-07-15

자료구조
StringBuilder : 문자열 누적 및 재사용List<Integer> : 약수 저장 및 정렬 (방법 2)알고리즘/기법
핵심 키워드
문제 분해
- n이 –1이 입력될 때까지 반복
- 1부터 n–1까지 모든 약수를 탐색하여, 나누어떨어지면
sum에 더하고StringBuilder에 “ + i” 형태로 누적- 반복 종료 후
sum == n인지 확인해 완전수 여부 출력핵심 로직 흐름
while (true) { n 입력 if (n == -1) break sum = 1 sb.setLength(0) sb.append(" = 1") for (i = 2; i < n; i++) { if (n % i == 0) { sb.append(" + ").append(i) sum += i } } if (sum == n) 출력(n + sb.toString()) else 출력(n + " is NOT perfect.") }예외 처리
- n = 1인 경우: 1은 완전수가 아니므로
“1 is NOT perfect.”출력
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
while (true) {
int n = Integer.parseInt(br.readLine());
if (n == -1) break;
int sum = 1;
sb.setLength(0);
sb.append(" = 1");
for (int i = 2; i < n; i++) {
if (n % i == 0) {
sb.append(" + ").append(i);
sum += i;
}
}
if (sum == n) {
System.out.println(n + sb.toString());
} else {
System.out.println(n + " is NOT perfect.");
}
}
}
}
문제 분해
- 약수는 짝을 이루므로 2부터 √n까지만 탐색
- i가 약수면 i와 n/i를 동시에 추가
String.join method로 최종 문자열 조립핵심 로직 흐름
for (i = 2; i <= √n; i++) { if (n % i == 0) { add i, add (n/i) (중복 방지) sum += i + (i != n/i ? n/i : 0) } } 정렬 후 " + " 구분자로 문자열 생성 sum == n 확인 후 출력예외 처리
- √n이 정수일 때 i == n/i 조건으로 중복 추가 방지
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
int n = Integer.parseInt(br.readLine());
if (n == -1) break;
List<Integer> divisors = new ArrayList<>();
divisors.add(1);
int sum = 1;
int root = (int) Math.sqrt(n);
for (int i = 2; i <= root; i++) {
if (n % i == 0) {
divisors.add(i);
if (i != n / i) divisors.add(n / i);
sum += i + (i != n / i ? n / i : 0);
}
}
if (sum == n) {
Collections.sort(divisors);
String result = String.join(" + ",
divisors.stream().map(String::valueOf).toArray(String[]::new));
System.out.println(n + " = " + result);
} else {
System.out.println(n + " is NOT perfect.");
}
}
}
}
방법 1
- 시간 복잡도: O(n)
- 공간 복잡도: O(n) (문자열 버퍼 및 출력용)
방법 2
- 시간 복잡도: O(√n · log√n) (정렬 포함)
- 공간 복잡도: O(√n)
StringBuilder 초기화 방법을 몰라 블로그를 참고했고, String Joiner 또한 배울 수 있었다.StringJoiner나 새 인스턴스 생성은 가독성을 높이고 초기 용량 비용이 크지 않을 때 유용하다.StringBuilder 재사용(setLength(0))은 Garbage Collection 부담을 줄이고, 반복 생성/삭제 비용을 절감해 성능에 민감한 상황에서 더 효율적이다.
- Garbage Collection 부담을 줄인다는건 JVM이 힙(Heap) 메모리에서 “쓸모없어진 객체”를 찾아서 삭제하고 메모리를 회수하는 작업을 덜 하게 만든다는 의미이다.
StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)는 구분자를 포함해 String을 출력해야할 때 유용하다.비슷한 유형 (GPT 추천):
확장 문제 (GPT 추천):