728x90
문제 설명
'A'와 'B'로만 구성된 문자열 S가 주어진다. 다음 동작을 더 이상 수행할 수 없을 때까지 반복한다:
- 문자열 S에서 첫 번째로 등장하는 부분 문자열 "ABB"를 찾는다.
- 그 위치를 i라고 할 때, 𝑆𝑖와 𝑆𝑖+1를 각각 'B'와 'A'로 바꾸고, 𝑆𝑖+2를 문자열에서 제거한다.
- 즉, "ABB"를 "BA"로 변환한다.
- 문자열에 "ABB"가 더 이상 존재하지 않을 때까지 이 과정을 반복한다.
반복이 끝난 후의 문자열 S를 출력하는 프로그램을 작성해야 한다.
문제 해결 방법
이 문제는 문자열에서 특정 패턴("ABB")을 찾아 변환하는 작업을 반복적으로 수행해야 한다. 그러나 문자열의 길이가 최대 5×10^5이므로 단순한 탐색으로는 시간 초과가 발생한다.
효율적인 해결을 위해 다음과 같은 방법을 사용한다
1. 연결 리스트를 이용한 시뮬레이션
- 문자열의 각 문자를 노드로 갖는 연결 리스트를 만든다.
- 각 노드는 이전 노드와 다음 노드에 대한 포인터를 가진다.
- 이렇게 하면 문자 삭제와 삽입이 O(1)시간에 가능하다.
2. 패턴 발생 위치 추적
- 문자열을 처음부터 탐색하여 'A'인 위치를 큐에 저장한다.
- 각 위치에서 'ABB' 패턴이 형성되는지 확인한다.
- 변환이 발생하면 인접한 위치에서 새로운 'ABB' 패턴이 생길 수 있으므로, 해당 위치들을 큐에 추가한다.
3. 알고리즘 단계
- 초기화
- 문자열을 문자 리스트로 변환하고, 각 문자에 대해 이전 노드와 다음 노드를 저장한다.
- 각 위치에 대해 이전 노드(prev), 다음 노드(next)를 저장하는 배열을 만든다.
- 'A'인 위치를 모두 큐에 넣는다.
- 변환 반복
- 큐에서 위치를 하나씩 꺼내어 처리한다.
- 해당 위치에서 'ABB' 패턴이 있는지 확인한다.
- 𝑆 𝑖 = ′ 𝐴 ′, 𝑆 𝑛 𝑒 𝑥 𝑡 𝑖 = ′𝐵 ′ 인 경우
- 패턴이 있으면 변환을 수행한다:
- 𝑆 𝑖 를 ′𝐵 ′ 로, 𝑆 𝑛 𝑒 𝑥 𝑡 𝑖 를 ′ 𝐴 ′ 로 변경
- 𝑆 𝑛 𝑒 𝑥 𝑡 𝑛 𝑒 𝑥 𝑡 𝑖 를 삭제하고 연결 리스트를 업데이트
- 변환으로 인해 영향을 받을 수 있는 인접한 위치들을 큐에 추가한다.
- 결과 생성
- 변환이 모두 끝나면 연결 리스트를 순회하여 최종 문자열을 생성한다.
백준 ABB to BA (Hard) 32293 파이썬(Python) 정답 코드
import sys
def main():
import sys
input = sys.stdin.readline
t = int(input())
MAX_N = 5 * 10**5 + 5
for _ in range(t):
n = int(input())
S = input().strip()
chars = list(S)
n = len(chars)
# 노드의 이전 위치와 다음 위치를 저장하는 배열
prev = [-1] * n
next = [-1] * n
for i in range(n):
if i > 0:
prev[i] = i - 1
if i < n - 1:
next[i] = i + 1
# 'A'인 위치를 큐에 저장
from collections import deque
queue = deque()
in_queue = [False] * n
for i in range(n):
if chars[i] == 'A':
queue.append(i)
in_queue[i] = True
while queue:
i = queue.popleft()
in_queue[i] = False
# 현재 위치에서 'ABB' 패턴 확인
if chars[i] != 'A':
continue
if next[i] == -1 or next[next[i]] == -1:
continue
j = next[i]
k = next[j]
if chars[j] == 'B' and chars[k] == 'B':
# 변환 수행
chars[i] = 'B'
chars[j] = 'A'
# 노드 k 삭제
next[j] = next[k]
if next[k] != -1:
prev[next[k]] = j
# 변환으로 인해 영향을 받을 수 있는 위치들을 큐에 추가
for idx in [prev[prev[i]] if prev[i] != -1 else -1, prev[i], i, j, next[j]]:
if idx != -1 and chars[idx] == 'A' and not in_queue[idx]:
queue.append(idx)
in_queue[idx] = True
# 결과 문자열 생성
result = []
idx = 0
while prev[idx] != -1:
idx = prev[idx]
while idx != -1:
result.append(chars[idx])
idx = next[idx]
print(''.join(result))
if __name__ == "__main__":
main()
백준 32293 ABB to BA (Hard) 파이썬 코드 설명
1. 데이터 구조 초기화
- chars: 문자열의 각 문자를 리스트로 저장한다.
- prev, next: 각 위치에서 이전 위치와 다음 위치를 저장하는 배열을 생성한다.
- 초기화 시, prev[i] = i - 1, next[i] = i + 1로 설정한다.
- 문자열의 처음과 끝에서는 prev[0] = -1, next[n - 1] = -1로 설정한다.
2. 큐 초기화
- 문자열을 처음부터 탐색하여 문자 'A'인 위치를 모두 큐에 넣는다.
- in_queue 배열을 사용하여 중복 추가를 방지한다.
3. 변환 반복
- 큐에서 위치를 하나씩 꺼내어 처리한다.
- 현재 위치 i에서 다음을 확인한다:
- chars[i] == 'A'인지 확인한다.
- next[i]와 next[next[i]]가 존재하는지 확인한다.
- chars[next[i]] == 'B'이고 chars[next[next[i]]] == 'B'인지 확인한다.
- 조건이 모두 만족하면 변환을 수행한다:
- chars[i] = 'B'
- chars[next[i]] = 'A'
- 노드 next[next[i]]를 삭제하고 연결 리스트를 업데이트한다.
- next[next[i]]를 next[next[next[i]]]로 업데이트한다.
- next[next[next[i]]]가 존재하면 그 노드의 prev를 next[i]로 설정한다.
- 변환으로 인해 새로운 'ABB' 패턴이 생길 수 있는 위치들을 큐에 추가한다:
- prev[prev[i]], prev[i], i, next[i], next[next[i]] 위치 중 유효한 위치를 큐에 넣는다.
- 해당 위치의 문자가 'A'이고 아직 큐에 없을 때만 추가한다.
4. 결과 문자열 생성
- 연결 리스트를 순회하여 최종 문자열을 생성한다.
- prev가 -1인 노드부터 시작하여 next를 따라가며 문자를 추가한다.
백준 32293 ABB to BA (Hard) 제출 결과
도움이 되셨다면 공감과 댓글 부탁드립니다.
728x90
'Python > 백준' 카테고리의 다른 글
백준 GLCCDM [32649] 파이썬(Python) 코드 + 해설 (1) | 2024.11.13 |
---|---|
백준 gcd와 최단 경로 [32632] 파이썬(Python) 코드 + 해설 (0) | 2024.11.12 |
백준 토마토 [7576] 파이썬(Python) 코드 + 해설 (1) | 2024.11.10 |
백준 KCM Travel [10217] 파이썬(Python) 코드 + 해설 (4) | 2024.11.09 |
백준 원판 돌리기 [17822] 파이썬(Python) 코드 + 해설 (0) | 2024.11.08 |