문제 링크:
문제:
상근이는 수학시간에 딴 짓을 하다가 선생님께 걸렸다. 선생님은 상근이에게 이번 주말동안 반성하라며 엄청난 숙제를 내주었다.
선생님이 상근이에게 준 종이에는 숫자와 알파벳 소문자로 되어있는 글자가 N줄있다. 상근이는 여기서 숫자를 모두 찾은 뒤, 이 숫자를 비내림차순으로 정리해야한다. 숫자의 앞에 0이 있는 경우에는 정리하면서 생략할 수 있다.
글자를 살펴보다가 숫자가 나오는 경우에는, 가능한 가장 큰 숫자를 찾아야 한다. 즉, 모든 숫자의 앞과 뒤에 문자가 있거나, 줄의 시작 또는 끝이어야 한다.
예를 들어, 01a2b3456cde478에서 숫자를 찾으면 1, 2, 3456, 478이다.
선생님이 준 종이의 내용이 주어졌을 때, 상근이의 숙제를 대신하는 프로그램을 작성하시오.
입력:
첫째 줄에 종이의 줄의 개수 N이 주어진다. (1 ≤ N ≤ 100)
다음 N개의 줄에는 각 줄의 내용이 주어진다. 각 줄은 최대 100글자이고, 항상 알파벳 소문자와 숫자로만 이루어져 있다.
출력:
종이에서 찾은 숫자의 개수를 M이라고 하면, 출력은 M줄로 이루어져야 한다. 각 줄에는 종이에서 찾은 숫자를 하나씩 출력해야 한다. 이때, 비내림차순으로 출력해야 한다. 비내림차순은 내림차순의 반대인 경우인데, 다음 수가 앞의 수보다 크거나 같은 경우를 말한다.

문제이해:
이는 예시를 통해 바로 어떻게 출력되는지 알아볼 수 있다.

즉 알파벳이 나오기 전까지 연속된 숫자를 따로 저장해야 한다.
002와 같은 경우는 2로 대신한다.
구현 방식:
입력 문자열에서 숫자만 추출하는 기능을 구현할 때는 문자 하나하나를 순차적으로 읽으면서 조건에 따라 동작을 분기시키는 방식이 가장 직관적이다. 핵심은 숫자가 연속될 때 이를 하나의 숫자로 인식하고, 중간에 알파벳 등 숫자가 아닌 문자가 등장하면 그 시점을 기준으로 숫자를 끊어 저장하는 것이다.
구현할 때는 다음과 같은 방식으로 흐름을 잡는다:
- 문자 하나씩 순회하면서
- 숫자인 경우에는 StringBuilder에 계속 붙인다.
- 숫자가 아닌 문자가 등장하면, 지금까지 모아둔 숫자가 있다면 그걸 하나의 숫자로 만들어 리스트에 저장하고, StringBuilder를 초기화한다.
- 숫자 끝 처리도 중요하다. 입력이 숫자로 끝나는 경우에는 반복문이 끝난 후 마지막 숫자를 한 번 더 리스트에 넣어줘야 한다.
- 숫자 앞에 0이 붙을 수도 있기 때문에 일반적인 int나 long 타입 대신 BigInteger를 사용하면 원형 그대로 저장할 수 있다. 예를 들어 "a002b"처럼 선행 0이 있는 숫자도 "002" 그대로 다룰 수 있다.
- 숫자를 모두 모은 뒤에는 정렬을 해야 하므로, 수집한 리스트에 대해 정렬 메서드를 한 번 호출해주면 된다.
이런 식으로 조건에 따라 문자 처리 흐름을 잘 나눠주면 복잡한 정규식 없이도 충분히 정확한 숫자 추출이 가능하다.
이를 코드로 구현하면 다음과 같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Vector;
public class Main {
static Vector<BigInteger> resultVector= new Vector<>(); //결과를 담을 벡터 생성
//한 입력에 대해 숫자를 추출하는 메서드
public static void parseInteger(StringBuilder sb){
boolean numflag= false;
StringBuilder result=new StringBuilder();
for(int i=0; i<sb.length(); i++){
char c= sb.charAt(i);
//현재 검사하는 문자가 숫자면
if(Character.isDigit(c)){
result.append(c);
numflag=true;
}
//현재 검사하는 문자가 문자면
else if(Character.isLetter(c)){
numflag=false;
}
//플레그가 false이고 결과 안에 무언가 있으면
//즉 저장된 숫자를 백터에 저장해야 하는 경우
if(!numflag && result.length()!=0){
BigInteger b= new BigInteger(result.toString());
resultVector.add(b);
//결과 초기화
result=new StringBuilder();
}
// 마지막 문자인 경우 체크
if(i==sb.length()-1 && numflag){
BigInteger b= new BigInteger(result.toString());
resultVector.add(b);
//결과 초기화
result=new StringBuilder();
}
}
}
public static void main(String[] args) throws IOException {
int count; //입력 횟수
StringBuilder sb= new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
count = Integer.parseInt(br.readLine()); // 입력 횟수 읽기
for (int i = 0; i < count; i++) {
String str = br.readLine(); // 한 줄씩 입력 받기
sb.append(str);
parseInteger(sb); //한줄 전달
sb=new StringBuilder();
}
//벡터 정렬
Collections.sort(resultVector);
//결과 출력
for(BigInteger i : resultVector){
System.out.println(i);
}
}
}

마무리하며:
처음엔 단순히 문자열에서 숫자만 뽑는 작업이라 가볍게 생각했지만, 막상 구현에 들어가 보니 문자의 종류에 따라 처리 흐름을 나누고, 숫자의 종료 시점을 정확히 판단하는 것이 꽤 중요했다.
또한 BigInteger를 사용하지 않고 처음엔 int나 long으로 처리하려다 보니, 숫자 앞에 0이 붙는 경우나 매우 큰 숫자를 다룰 때 문제가 생겼고, 그때서야 자료형 선택이 얼마나 중요한지 체감했다. 결국 BigInteger로 바꾸면서 선행 0도 그대로 유지하고, 자료형 범위 초과 문제도 자연스럽게 해결할 수 있었다.
전체적으로 보면 알고리즘 자체는 단순하지만, 디테일에서 완성도가 갈리는 문제였다. 한 글자씩 직접 처리하면서 흐름을 통제하고, 조건마다 분기해 정확하게 판단해주는 과정이 중요했다.
감사합니다.
'코딩 테스트' 카테고리의 다른 글
| [백준] 2852 NBA 농구 (JAVA) (7) | 2025.07.10 |
|---|---|
| [백준] 10709 기상 캐스터 (JAVA) (3) | 2025.07.09 |
| [백준] 4659 비밀번호 발음하기 (JAVA) (1) | 2025.07.06 |
| [백준] 2910 빈도 정렬 (JAVA) (1) | 2025.07.04 |
| [백준] 2828 사과 담기 게임 (JAVA) (1) | 2025.07.04 |