📣 솔브드 그랜드 아레나 📣

2023. 8. 16. 21:21개발/👾 PS

 

 

 

솔브드에서 하는 그랜드 아레나 참가했다

그래도 나름 알고리즘 공부 열심히 해서

3솔은 할 줄 알았는데

.....2솔 했다

그것도 브론즈로 2개 풀었다

보니까 나머지 문제는 다 골드에서 다이아더라

실버 달라구여 실버 (찡찡)

 

암튼 내 실력을 여실히 깨닫고 낑낑댔던 문제(I번) 오답 노트나 하련다...

 

우선 나온 문제들 유형을 간단하게 살펴봤는데 역시나 그래프랑 트리 문제가 대부분을 차지했다.

수학 문제랑 그리디 문제도 꽤나 나왔다.

이제 곧 SUAPC Summer 나갈 건데 그전에 트리 공부 좀 더 해놔야겠다.

 

 

앞에 쉬운 두 문제를 30분컷 하고 나서 이 문제만 2시간 반이나 붙들고 있었는데 결국 못 풀었다.

https://www.acmicpc.net/problem/28709

 

28709번: 와일드카드 괄호 문자열

각 테스트케이스마다 한 줄에 하나씩, ‘?’ 문자를 ‘(’이나 ‘)’로, ‘*’ 문자를 ‘(’, ‘)’로 이루어진 길이가 $0$ 이상인 원하는 문자열로 대체하여 $S$를 올바른 괄호 문자열로 만들 수

www.acmicpc.net

 

일단 보자마자 예전에 비슷한 문제 스택으로 풀었던 게 생각나서

스택으로 풀기 시작!

 

word에 입력값 넣기

 

word에서 하나씩 pop해서 스택에 넣을지 말지 판별( word 빌 때까지 반복 )

 

"("  "*"  "?" 는 스택에 바로 집어넣고

")" 는 스택이 비어있으면 바로 NO 출력하고 return

스택이 비어있지 않으면 스택의 top 확인해서 "(" 면 pop해주기

 

 while 문 빠져나왔을 때

스택이 비어있으면 YES 출력

스택 안에 남아있는 게   ["("   ->   "*" / "?" ] 이런 순서면 YES 아니면 NO 출력

 

import sys
input = sys.stdin.readline
word = []

n = int(input())


def mirror(word):
    word.pop(-1)
    stack = []
    while word:
        curr = word.pop(0)
        if curr == "(" or curr == "?" or curr == "*":
            stack.append(curr)
        else:
            if len(stack) > 0:
                if stack[-1] == "(":
                    stack.pop(-1)
                elif stack[-1] == "?" or stack[-1] == "*":
                    continue
            else:
                print("NO")
                return

    if len(stack) == 0:
        print("YES")
        return
    else:
        if stack[-1] == "?" or stack[-1] == "*":
            print("YES")
            return
        else:
            print("NO")
            return


for i in range(n):
    word = list(input())
    mirror(word)
    word.clear()

 

아니 근데 문제 잘못 읽어서( ? 랑 * 차이 완전 무시하고 풀어버림... )

시간 허비를 엄청나게 했다.

이건 막판에 멘붕 와서 갈아엎은 코드...

 

import sys
input = sys.stdin.readline
word = []
Yes = [[], ["*"], ["*"], ["(", "?", "*"]]
global ans
ans = True

n = int(input())


def mirror(word):
    print(word)
    global ans
    stack = []
    while word:
        curr = word.pop(0)
        if curr == "(" or curr == "*" or "?":
            stack.append(curr)
            print(stack)
        else:
            if len(stack) > 0:
                if stack[-1] == "(" or "?":
                    stack.pop(-1)
                    print(stack)
                else:
                    stack.append(curr)
                    print(stack)
            else:
                print("NO")
                return

    if len(stack) == 0:
        print("YES")
        return
    else:
        while stack:
            now = stack.pop(0)
            print(now)
            if now == "(":
                now = 0
            elif now == ")":
                now = 1
            elif now == "?":
                now = 2
            else:
                now = 3
            print(stack[0], Yes[now])
            if stack[0] in Yes[now]:
                ans = True
            else:
                ans = False

        if ans:
            print("YES")
        else:
            print("NO")


for i in range(n):
    word = list(input())
    word.pop(-1)
    mirror(word)
    word.clear()

 

근데 이 코드도 막판에 완전 큰 오류 발견해서 고치려고 했지만.. 시간이 모자랐다...

 

 

아래 코드는 솔브드에서 제공한 모범 답안

https://solved.ac/arena/2/editorial

 

solved.ac

알고리즘 문제해결 학습의 이정표 🚩 Baekjoon Online Judge 문제들의 난이도 및 티어 정보를 제공하는 사이트입니다.

solved.ac

import sys


def input(): return sys.stdin.readline().rstrip()


def solve(s):
    s = list(s)
    # 문자열에 '*' 이 있는 경우
    if s.count('*') >= 1:
        cnt = 0
        for c in s:
            if c == '*':   # A : 첫 '*'이 나타날 때까지의 문자열
                break
            if c == ')':
                cnt -= 1
            else: 
                cnt += 1   #'?' -> '(' 취급
            
            # cnt가 음수가 되는 순간(짝을 이루지 못한 ')'가 등장하는 순간) False 반환 
            if cnt < 0:
                return False
                
        cnt = 0
        for c in s[::-1]:
            if c == '*':    # C : 문자열 끝에서부터 마지막 '*'까지의 문자열
                break
            if c == '(':
                cnt -= 1
            else:			# '?' -> ')' 취급
                cnt += 1
            # cnt가 음수가 되는 순간(짝을 이루지 못한 '('가 등장하는 순간) False 반환
            if cnt < 0:
                return False
        # B : A와 C를 제외한 나머지 문자열 -> 시작과 끝이 '*'로 되어 있으므로 항상 True
        # A와 C를 모두 통과했다면 True 반환
        return True
        
    # 문자열에 '*'이 포함되지 않은 경우
    
    # 문자열의 길이가 홀수인 경우 무조건 짝이 없는 '(' or ')' or '?'가 등장하므로 False 반환
    if len(s) % 2 != 0:
        return False
    open_ = s.count('(')
    close = s.count(')')
    # '('나 ')'의 개수가 문자열 길이의 반보다 많으면 False 반환 -> 짝을 못 이루는 애들이 생김
    if open_ > len(s) // 2 or close > len(s) // 2:
        return False

    cnt = 0
    for c in s:
    # '?'를 '('나 ')'로 치환 -> 이때 '('나 ')'의 개수가 문자열 길이의 반과 동일하면 해당 문자로 치환해줘선 안 된다 -> 짝을 이루지 못하게 됨
        if c == '?':
            # '?' -> '(' 먼저(그리디)
            if open_ < len(s) // 2:
                c = '('
                open_ += 1
            # '?' -> ')'
            else:
                c = ')'
        if c == '(':
            cnt += 1
        else:
            cnt -= 1
        # cnt가 음수가 되면(짝을 이루지 못하는 ')'가 생기면) False 반환
        if cnt < 0:
            return False
    return True


def main():
    T = int(input())
    for _ in range(T):
        s = input()
        print("YES" if solve(s) else "NO")


if __name__ == "__main__":
    main()

 

어렵다....

괄호 문제는 유형으로 외워두면 좋을 듯...

스택에 넣으면 너무 단편적으로 판단하고 pop해버려서 이런 복잡한 조건('?' '*')이 포함되어 있을 땐

스택을 안 쓰는 게 좋을 것 같다.

 

앞에서부터 탐색, 뒤에서부터 탐색 둘 다 하는 방법도 기억해둬야겠다.

 

평범한 괄호 문제 같은 경우는

for문으로 문자열 탐색하면서

'(' -> cnt ++

')' -> cnt --

cnt < 0 되는 순간 False 반환해버리는 식으로 풀면 될 것 같다

 

이제 괄호 문제는 안 틀릴거야아아아아🔥🔥

 

 


 

 

끝나고 왹파티🎉🎉🎉🎉

 

 

 

진짜 역대급으로 알차구 재밌었다...ㅎㅎㅎ

'개발 > 👾 PS' 카테고리의 다른 글

[ 최소 공통 조상 ] 알고리즘  (1) 2023.08.23
[ 세그먼트 트리 ] 알고리즘  (0) 2023.08.23
[ 이진 트리 ] 알고리즘  (0) 2023.07.26
[ 트라이 ] 알고리즘  (0) 2023.07.22
[ 트리 ] 알고리즘  (0) 2023.07.19