[C++] 백준(BOJ) - 2870 : 수학숙제

인프런에 있는 큰돌님의 강의 10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트를 듣고 정리한 필기입니다.

문제

백준(BOJ) - 2870 : 수학숙제(링크)

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

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

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

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

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

입력

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

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

출력

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

예제 입력

2
lo3za4
01

예제 출력

1
3
4

알고리즘

  1. 문자열
  2. 정렬
  3. 파싱

풀이

  • 100자리의 수 long long 형으로도 커버가 안된다
    • string 형으로 풀이 후 변환
  • 숫자를 덧붙여 나가며 문자열을 만들어나가는 logic
  • 숫자 맨앞에 붙은 0을 제거하는 logic
    • 매개변수 참조로 전달(값 직접 변환)
    • ‘0000’과 같은 수 모두 사라졌을 때 반례 check
  • string의 비내림차순 custom operator 구현

코드

// 문자열
#include <bits/stdc++.h>
using namespace std;

int n;
vector<string> v;

void go(string &tmp) // 참조로 전달 => 값을 직접 변환 가능하다
{
    while (true)
    {
        if (tmp.size() && tmp.front() == '0') tmp.erase(tmp.begin()); // 앞부분 0 이라면 제거 
        // front를 참조하기 이전에 size를 체크해야 한다(참조 에러 방지)
        else break;
    }

    if (tmp.size() == 0) tmp = "0"; // 모두 제거 되었다면 원래 숫자는 0이다
    v.push_back(tmp); // 배열에 담기
    tmp = ""; // 빈 문자열로 다시 초기화
    return;
}

// string의 비내림차순 Custom Operator
bool cmp(string a, string b)
{
    if (a.size() == b.size()) return a < b;
    return a.size() < b.size();
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n;
    for (int i = 0; i < n; i++)
    {
        string str;
        cin >> str;
        string tmp = "";

        for (int j = 0; j < str.size(); j++)
        {
            // 만약 숫자라면 string 형 tmp 변수에 더해나감
            if (isdigit(str[j])) tmp += str[j];
            // 문자를 만났을 때 go 함수 발동
            else if(tmp.size()) go(tmp);
        }

        // 숫자로 남고 끝났을 때 실행
        if (tmp.size()) go(tmp);
    }

    sort(v.begin(), v.end(), cmp);

    for (auto i : v) cout << i << '\n';

    return 0;
}

평가

  • 숫자가 큰 문제의 경우 string으로 풀 생각을 할 수 있어야한다
  • string 형으로 만든 숫자의 대소 비교는 cmp를 만들어서 비교한다
  • 참조로 매개변수를 받는 것에 대해 익숙해 질 정도로 연습이 필요하다
  • string 형의 front, end 등 지점을 참조 할때는 항상 size가 0이 아닌지를 확인하여서 참조 에러를 없애야 한다
  • 반례를 생각하자

© 2023 Jinsoo Lee. All rights reserved.

Powered by Hydejack v9.1.6