
오늘 문제는 스택 자료 구조 유형의 문제에서 기본?이 되는 괄호 문제입니다.
오늘도 집중해봅시다!
| 시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 |
|---|---|---|---|---|---|
| 1 초 | 128 MB | 221883 | 105294 | 75518 | 46.177% |
괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다.
여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다.
입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다.
출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다.
6
(())())
(((()())()
(()())((()))
((()()(()))(((())))()
()()()()(()()())()
(()((())()(
NO
NO
YES
NO
YES
NO
3
((
))
())(()
NO
NO
NO
ICPC > Regionals > Asia Pacific > Korea > Nationwide Internet Competition > Daejeon Nationalwide Internet Competition 2012 G번
이번 문제는 괄호 문자열이 올바른 괄호 문자열(VPS, Valid Parenthesis String)인지 판단하는 문제입니다. 주어진 문자열이 올바른 VPS인지 판단하기 위해서는 괄호의 열림과 닫힘이 올바르게 짝지어져야 합니다.
이 문제를 해결하기 위해 두 가지 접근 방식을 사용했습니다:
(와 닫힘 괄호 )의 개수를 추적하여 올바른 괄호 문자열인지 확인합니다.스택을 사용하여 괄호의 짝을 맞추는 방법입니다. 열림 괄호 (는 스택에 추가하고, 닫힘 괄호 )는 스택에서 마지막으로 추가된 열림 괄호와 짝을 맞춰 제거합니다. 만약 닫힘 괄호를 처리할 때 스택이 비어 있다면, 이는 올바르지 않은 문자열로 판단합니다.
import sys
T = int(sys.stdin.readline().strip())
for _ in range(T):
ps = sys.stdin.readline().strip()
stack = []
for i in ps:
if i == '(':
stack.append(i)
else:
if stack:
stack.pop()
else:
stack.append(i)
break
if len(stack):
print('NO')
else:
print('YES')
(가 나오면 스택에 추가하고, )가 나오면 스택에서 (를 제거합니다.)를 처리할 때 스택이 비어 있으면 올바르지 않은 괄호 문자열로 판단하고 반복을 중단합니다.YES를 출력하고, 그렇지 않으면 NO를 출력합니다.T: 테스트 케이스의 수ps의 길이를 N이라고 할 때, 각 테스트 케이스에서 반복문은 N번 수행됩니다.append, pop)은 O(1) 시간 복잡도를 가집니다.따라서, 각 테스트 케이스에 대해 반복문이 N번 수행되므로, 각 테스트 케이스에 대한 시간 복잡도는 입니다.
전체적으로 T개의 테스트 케이스에 대해 이 작업이 반복되므로, 전체 시간 복잡도는 입니다.
이 방법에서는 스택 대신 total 변수로 열림 괄호와 닫힘 괄호의 균형을 추적합니다. 열림 괄호 (가 나오면 total을 증가시키고, 닫힘 괄호 )가 나오면 total을 감소시킵니다.
import sys
T = int(sys.stdin.readline().strip())
for _ in range(T):
ps = sys.stdin.readline().strip()
total = 0
for i in ps:
if i == '(':
total += 1
else:
total -= 1
if total < 0:
print("NO")
break
if total > 0:
print("NO")
elif total == 0:
print('YES')
total 변수는 열림 괄호 (의 개수와 닫힘 괄호 )의 개수 차이를 기록합니다.total이 0보다 작아지면 이미 닫힘 괄호가 너무 많아졌다는 의미이므로 그 즉시 NO를 출력하고 반복을 중단합니다.total이 0이면 올바른 괄호 문자열이므로 YES를 출력하고, 그렇지 않으면 NO를 출력합니다.T: 테스트 케이스의 수ps의 길이를 N이라고 할 때, 각 테스트 케이스에서 반복문은 N번 수행됩니다.if) 및 변수 연산은 O(1) 시간 복잡도를 가집니다.따라서, 각 테스트 케이스에 대한 시간 복잡도는 입니다.
전체적으로 T개의 테스트 케이스에 대해 이 작업이 반복되므로, 전체 시간 복잡도는 입니다.
하지만! 실질적인 속도는 카운팅을 이용한 방법이 더 빠를것입니다.
그 이유는 다음과 같습니다:
total)를 사용하여 카운팅합니다. 이 변수는 CPU 캐시에서 관리될 수 있기 때문에 접근 속도가 매우 빠릅니다.append와 pop 연산이 자주 일어나게 됩니다. 이러한 연산들은 개별적으로는 O(1)이지만, 메모리 할당이나 리스트 크기 증가에 따라 약간의 오버헤드가 발생할 수 있습니다.total 변수에 더하고 빼는 연산만을 수행하므로, 연산 자체가 매우 간단합니다.append와 pop 연산이 필요하며, 스택의 상태를 계속 관리해야 합니다. 비록 각 연산이 O(1)이라 하더라도, 실제 실행 시의 오버헤드는 카운팅 방법보다 클 수 있습니다.total 값이 음수가 되는 순간 바로 NO를 출력하고 반복을 종료할 수 있습니다. 이 경우, 루프를 조기에 종료하여 불필요한 연산을 줄일 수 있습니다.실제 코드 속도를 보더라도 다음과 같이 두 번째가 빠른 것을 확인할 수 있습니다.

예제 입력 2 결과
19.12669801712036

예제 입력 2 결과
8.185030937194824
이번 문제에서는 괄호의 짝을 맞추는 방법을 스택을 이용한 방법과 단순한 카운팅 방법으로 해결했습니다. 스택을 이용한 방법은 괄호 짝을 추적하는 데 직관적이며, 카운팅 방법은 메모리 사용량을 줄이는 데 유리합니다. 두 가지 방법 모두 효율적이며 문제의 요구 사항을 충족합니다.
이 문제를 통해 스택과 문자열 처리에 대한 기초적인 개념을 다시 한 번 복습할 수 있었으며, 이러한 문제들은 코딩 테스트에서 자주 출제되므로 익숙해져야 합니다. 끝까지 집중해서 다음 문제들도 차근차근 해결해 나가봅시다!
전체 코드는 저의 깃허브에서 확인하실 수 있습니다.
읽어주셔서 감사합니다!

더 나은 개발자가 될거야!!💪