[PS] BOJ 32767 / 문자열 줄이기

[PS] BOJ 32767 / 문자열 줄이기
문제 링크: https://www.acmicpc.net/problem/32767
Thumbnail: Photo by Diya Pokharel / Unsplash

처음에 브루투 포스 방식으로 풀었는데, 당연하게도 시간 초과를 맞닥뜨렸습니다..

문제

알파벳 소문자로 구성된 길이 \(N\)의 문자열 \(S\)가 주어진다.

\(S\)에 대하여 문자열 줄이기를 \(M\)번 시행한다. 문자열 줄이기의 과정은 다음과 같다.

  •  \(S\)에 포함된 문자 중 사전 순으로 가장 앞서는 문자를 하나 제거한다. 이때 가장 앞서는 문자가 여러 개일 경우 그 중 제일 앞에 위치한 문자를 하나 제거한다.

문자열 줄이기를 \(M\)번 시행한 뒤의 문자열 \(S\)를 구하자.

입력

첫째 줄에 1,000보다 작거나 같은 자연수 \(N\)이 주어진다.

출력

첫 번째 줄에 두 정수 \(N\)과 \(M\)이 공백으로 구분되어 주어진다. \((0 \le M \less N \le 3 \times 10^5)\)

두 번째 줄에 알파벳 소문자로 구성된 길이 \(N\)의 문자열  \(S\)가 주어진다.

풀이

문자열을 정렬하고, 하나씩 지워가며... 하는 풀이로는 시간 초과가 발생한다!
하지만, 지워야 하는 문자를 파악해두고 출력할 때 이를 고려한다면 어떨까?

먼저, \(S\)의 각 문자가 몇개씩 들어있는지 개수를 센다.

이후, 최대 M개까지 문자를 지운다는 점을 고려해, \(S\)의 각 문자들을 몇 개 제거해야할 지 기록한다. 만약 문자 \(c\)가 \(i\)개 있다면, \(i\)가 \(M\)보다 작다면 \(c\)를 아예 삭제하고, 그렇지 않다면 \(M\)개 만큼만 삭제하면 된다. 이를 \(S\)의 각 문자들을 사전상 빠른 순서대로 반복하며 진행한다.

마지막으로, 미리 기록해 둔 정보를 토대로 문자열의 각 문자를 출력할지 말지 판단하면 된다.

코드

from sys import stdin

N, M = map(int, stdin.readline().strip().split())
S = stdin.readline().strip()

# S를 이루는 각 문자의 개수를 센다.
char_count = {}
for c in S:
    if c not in char_count:
        char_count[c] = 1
    else:
        char_count[c] += 1

# 지워야 하는 문자들을 미리 기록해 둔다.
deleted = {}
for c in sorted(char_count):
    if char_count[c] > M:
        deleted[c] = M
        break
    else:
        deleted[c] = char_count[c]
        M -= char_count[c]

# 미리 기록해 둔 정보를 토대로, 문자들을 지워서 출력한다.
for c in S:
    if c in deleted:
        if deleted[c] > 0:
            deleted[c] -= 1
        else:
            print(c, end="")
    else:
        print(c, end="")
print()

solution.py