[파이썬] 백준 28709 : 와일드카드 괄호 문자열 (골드1)
28709번: 와일드카드 괄호 문자열
각 테스트케이스마다 한 줄에 하나씩, ‘?’ 문자를 ‘(’이나 ‘)’로, ‘*’ 문자를 ‘(’, ‘)’로 이루어진 길이가 $0$ 이상인 원하는 문자열로 대체하여 $S$를 올바른 괄호 문자열로 만들 수
www.acmicpc.net
문제
풀이
0. 방향성 생각
- *이 있는 케이스와 없는 케이스로 나눈다.
- 왜 와이 - > 입력 문자열 S를 split('*')을 통해 나누면 항상 다음의 케이스로 나누어진다.
- S = *A꼴 -> string = ['',A] : 왼쪽에서 '('를 무한정 공급 가능하다. 뒤에서부터 순회해서 (개수가 ?)개수랑 일치시킨다.
- S = A*꼴 -> string = [A,''] : 오른쪽에서 ')'를 무한정 공급 가능하다. 순회해서 (?개수가 )개수랑 일치시킨다.
- S = *A*꼴 -> string = ['',A,''] : 항상 올바른 문자열이므로 체크할 필요가 없다.
- S = A*B꼴 -> string = [A,B] : case1과 case2 경우가 동시에 있는 경우.
- S = S (별이 없는 경우)
- 위 4가지 케이스에 대해서는 별표가 존재하고 이 때 따로 처리를 해준다.
- *이 존재하는 경우 리스트의 맨 앞, 뒤만 체크하면 된다.
1. 입력
from collections import deque
import sys
input = lambda : sys.stdin.readline().rstrip()
2. *이 없는 경우 문자열 처리 함수 정의
def nstar(s):
if s[0] == ')' or s[-1] == '(':
return False
l,m,r = 0,0,0
for i in s:
if i == '(': l += 1
elif i == ')': r += 1
else: m += 1
leng = len(s)
if l > leng//2 or r > leng//2:
return False
count = 0
for i in s:
if i == '?':
if l < leng//2:
i = '('
l += 1
else:
i = ')'
if i == '(': count += 1
else: count -= 1
if count < 0:
return False
return True
- 양 끝이 )이거나 (이면 올바른 문자열이 아니다.
- ( 혹은 )의 개수가 절반 이상이면 올바른 문자열을 만들 수 없다. (매칭 불가)
- 절반을 나눠서 앞쪽은 (로, 뒤쪽을 )로 치환
- ( 개수가 절반이 되기 전까지 ?는 계속 (로 치환한다. 넘어가면 )로 치환한다.
3. *이 왼쪽에 있는 경우 문자열 처리 함수 정의
def lstar(s):
q = deque(s)
count = 0
while q:
x = q.pop()
if x == '(': count -= 1
else: count += 1
if count < 0: return False
return True
- S = *A꼴, A의 왼쪽에 별이 존재하는 경우 문자열 처리
- 왼쪽에서 무한정 (을 공급할 수 있다. ?) 개수가 (보다 많아야한다. 많아지면 *로 처리가능함
3. *이 오른쪽에 있는 경우 문자열 처리 함수 정의
def rstar(s):
q = deque(s)
count = 0
while q:
x = q.popleft()
if x == ')': count -= 1
else: count += 1
if count < 0: return False
return True
- S = A*꼴, A의 오른쪽에 별이 존재하는 경우 문자열 처리
- 오른쪽에서 무한정 )을 공급할 수 있다. (? 개수가 )보다 많아야한다. 많앚이면 *로 처리가능함
5. 출력
for _ in range(int(input())):
string = input().split("*")
length = len(string)
if length == 1:
if len(string[0])%2: correct = False
else: correct = nstar(string[0])
elif length > 1:
s0,s1 = string[0], string[-1]
if s0 == '' and s1 == '': correct = True # string = *
elif s0 == '' and s1 != '': correct = lstar(s1) # string = *A
elif s0 != '' and s1 == '': correct = rstar(s0) # string = A*
elif s0 != '' and s1 != '': correct = rstar(s0) and lstar(s1) # string = A*B
if correct: print('YES')
else: print('NO')
- split으로 문자열을 substring으로 나누고 양 끝만 체크한다.
- *이 없는경우 (?)로만 이루어져있다. 이 때 길이가 짝수가 아니면 올바른 문자열을 만들 수 없다
- 짝수인 경우 nstar를 통해 체크한다.
전체코드
from collections import deque
import sys
input = lambda : sys.stdin.readline().rstrip()
def nstar(s):
if s[0] == ')' or s[-1] == '(':
return False
l,m,r = 0,0,0
for i in s:
if i == '(': l += 1
elif i == ')': r += 1
else: m += 1
leng = len(s)
if l > leng//2 or r > leng//2:
return False
count = 0
for i in s:
if i == '?':
if l < leng//2:
i = '('
l += 1
else:
i = ')'
if i == '(': count += 1
else: count -= 1
if count < 0:
return False
return True
def lstar(s):
q = deque(s)
count = 0
while q:
x = q.pop()
if x == '(': count -= 1
else: count += 1
if count < 0: return False
return True
def rstar(s):
q = deque(s)
count = 0
while q:
x = q.popleft()
if x == ')': count -= 1
else: count += 1
if count < 0: return False
return True
for _ in range(int(input())):
string = input().split("*")
length = len(string)
if length == 1:
if len(string[0])%2: correct = False
else: correct = nstar(string[0])
elif length > 1:
s0,s1 = string[0], string[-1]
if s0 == '' and s1 == '': correct = True # string = *
elif s0 == '' and s1 != '': correct = lstar(s1) # string = *A
elif s0 != '' and s1 == '': correct = rstar(s0) # string = A*
elif s0 != '' and s1 != '': correct = rstar(s0) and lstar(s1) # string = A*B
if correct: print('YES')
else: print('NO')
코멘트
별표 없는 경우가 굉장히 까다로웠던.... 처음에 스택으로 처리하려고 했는데 하나 고치면 자꾸 반례가 생겨서 개수세는 식으로 바꿨는데도 실패...
solved.ac - solved.ac Grand Arena #2
해설이 있는줄 모르고 한달넘게 고민... 매일 고민한건 아니지만 매주 1트는 했던거같은데 참고해서 성공
해설 방식처럼 치환하는게 항상 정답을 보장하냐에 대해서는 잘 모르겠어서 접근을 안했었는데 맞다네요.... 흠....
'Algorithm > Greedy' 카테고리의 다른 글
[파이썬] 백준 2109 : 순회강연 (골드3) (0) | 2023.12.12 |
---|---|
[파이썬] 백준 2258 : 정육점 (골드4) (0) | 2023.12.10 |
[파이썬] 백준 1781 : 컵라면 (골드2) (0) | 2023.11.30 |
[파이썬] 백준 18513 : 샘터 (골드4) (0) | 2023.10.22 |
[파이썬] 프로그래머스 : 단속카메라 (Lv.3) (0) | 2023.08.18 |
[파이썬] 프로그래머스 : 요격 시스템 (Lv.2) (0) | 2023.08.18 |
[파이썬] 프로그래머스 : 구명보트 (Lv.2) (0) | 2023.07.06 |
댓글