[백준] 2870 수학숙제 (JAVA)

2025. 7. 8. 16:25·코딩 테스트

문제 링크:

2870번: 수학숙제

 

문제:

상근이는 수학시간에 딴 짓을 하다가 선생님께 걸렸다. 선생님은 상근이에게 이번 주말동안 반성하라며 엄청난 숙제를 내주었다.

 

선생님이 상근이에게 준 종이에는 숫자와 알파벳 소문자로 되어있는 글자가 N줄있다. 상근이는 여기서 숫자를 모두 찾은 뒤, 이 숫자를 비내림차순으로 정리해야한다. 숫자의 앞에 0이 있는 경우에는 정리하면서 생략할 수 있다.

 

글자를 살펴보다가 숫자가 나오는 경우에는, 가능한 가장 큰 숫자를 찾아야 한다. 즉, 모든 숫자의 앞과 뒤에 문자가 있거나, 줄의 시작 또는 끝이어야 한다.

 

예를 들어, 01a2b3456cde478에서 숫자를 찾으면 1, 2, 3456, 478이다.

 

선생님이 준 종이의 내용이 주어졌을 때, 상근이의 숙제를 대신하는 프로그램을 작성하시오.

 

입력:

첫째 줄에 종이의 줄의 개수 N이 주어진다. (1 ≤ N ≤ 100)

다음 N개의 줄에는 각 줄의 내용이 주어진다. 각 줄은 최대 100글자이고, 항상 알파벳 소문자와 숫자로만 이루어져 있다.

 

출력:

종이에서 찾은 숫자의 개수를 M이라고 하면, 출력은 M줄로 이루어져야 한다. 각 줄에는 종이에서 찾은 숫자를 하나씩 출력해야 한다. 이때, 비내림차순으로 출력해야 한다. 비내림차순은 내림차순의 반대인 경우인데, 다음 수가 앞의 수보다 크거나 같은 경우를 말한다.

 

문제이해:

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

즉 알파벳이 나오기 전까지 연속된 숫자를 따로 저장해야 한다.

002와 같은 경우는 2로 대신한다.

 

구현 방식:

입력 문자열에서 숫자만 추출하는 기능을 구현할 때는 문자 하나하나를 순차적으로 읽으면서 조건에 따라 동작을 분기시키는 방식이 가장 직관적이다. 핵심은 숫자가 연속될 때 이를 하나의 숫자로 인식하고, 중간에 알파벳 등 숫자가 아닌 문자가 등장하면 그 시점을 기준으로 숫자를 끊어 저장하는 것이다.

구현할 때는 다음과 같은 방식으로 흐름을 잡는다:

  1. 문자 하나씩 순회하면서
    • 숫자인 경우에는 StringBuilder에 계속 붙인다.
    • 숫자가 아닌 문자가 등장하면, 지금까지 모아둔 숫자가 있다면 그걸 하나의 숫자로 만들어 리스트에 저장하고, StringBuilder를 초기화한다.
  2. 숫자 끝 처리도 중요하다. 입력이 숫자로 끝나는 경우에는 반복문이 끝난 후 마지막 숫자를 한 번 더 리스트에 넣어줘야 한다.
  3. 숫자 앞에 0이 붙을 수도 있기 때문에 일반적인 int나 long 타입 대신 BigInteger를 사용하면 원형 그대로 저장할 수 있다. 예를 들어 "a002b"처럼 선행 0이 있는 숫자도 "002" 그대로 다룰 수 있다.
  4. 숫자를 모두 모은 뒤에는 정렬을 해야 하므로, 수집한 리스트에 대해 정렬 메서드를 한 번 호출해주면 된다.

이런 식으로 조건에 따라 문자 처리 흐름을 잘 나눠주면 복잡한 정규식 없이도 충분히 정확한 숫자 추출이 가능하다.

 

이를 코드로 구현하면 다음과 같다.

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
'코딩 테스트' 카테고리의 다른 글
  • [백준] 2852 NBA 농구 (JAVA)
  • [백준] 10709 기상 캐스터 (JAVA)
  • [백준] 4659 비밀번호 발음하기 (JAVA)
  • [백준] 2910 빈도 정렬 (JAVA)
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준
    타임리프
    fetch join
    스프링 데이터 JPA
    객체지향
    최적화
    스프링 컨테이너
    JPA
    코딩 테스트
    스프링
    컬렉션
    BFS
    SOLID
    재귀
    mvc
    LocalDateTime
    예외 처리
    코딩테스트
    spring
    QueryDSL
    thymeleaf
    자바
    쿼리dsl
    불변객체
    SpringDataJpa
    dfs
    다형성
    쿼리
    Java
    예외처리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[백준] 2870 수학숙제 (JAVA)
상단으로

티스토리툴바