첫 번째 시도, 시간초과. 두 번째 약간의 힌트를 얻고 통과! 처음 생각하던 아이디어 그대로 풀었으면 시간 초과 안 나고 잘 풀었을 텐데 반복문을 두 번이나 쓰면서 시간초과로 실패했다. 그래도 문제가 아주 어렵지 않고, 마지막에 넣은 값을 빼는 스택을 활용한다는 아이디어만 바로 얻으면 금방 풀어낼 수 있다! 자 이제 풀어보자.
📝 백준 10799 쇠막대기
https://www.acmicpc.net/problem/10799
서로 마주 보는 ()는 레이저, 나머지 괄호 (--)는 막대기를 의미한다. 예시 이미지에서 첫 번째 괄호는 레이저지만, 앞 뒤로 괄호가 없어서 막대기가 없다는 의미이므로 자를 막대기가 없는 것! 이렇게 잘린 막대기의 수를 찾으면 된다.
💡 문제 풀이 아이디어
"("를 만나면 막대기의 시작을 의미한다. 그리고 ")" 만나면 가장 마지막에 시작한 막대기의 끝을 의미한다. '가장 마지막에 시작한' 에서 막대기를 저장하는 자료 구조로 스택을 활용할 수 있다는 아이디어를 얻을 수 있다. ( 를 만나서 막대기가 여전히 있음을 저장하고, 레이저를 만나면 살아있는 막대기의 개수를 세서 잘린 막대기 수를 셀 수 있다.
그림을 보면서 생각해봤을 땐, 레이저가 동작했을 때 남아있는 막대기의 수를 더하고, 막대기가 끝났을 때 남은 막대기 1을 더해주면 된다. (아이패드 애플 펜슬 인식이 이상해서 +가 이상하게 그려졌지만, 어쨌든 O를 그린 개수만큼 더해지는 것!)
📝 문제 풀이 (파이썬)
# 시간 복잡도 O(N)
arr = input()
stack = []
result = 0
for i, x in enumerate(arr):
# ( 를 만나면 막대기를 시작
if x == "(":
stack.append("(")
# ) 를 만났는데, 이전 막대기가 ( (레이저 O)
elif arr[i - 1] == "(" and x == ")":
stack.pop() # stack에서 막대기를 빼고,
result += len(stack) # 지금까지 살아있는 막대기의 수를 더한다
# ) 를 만나면 막대기 끝 (레이저 X)
else:
stack.pop() # stack에서 막대기를 빼고,
result += 1 # 남은 막대기 수 하나를 더한다
print(result)
여기서 몇 가지 보완, 수정을 한다면, enumerate로 사용하지 않고 이전값을 저장하는 변수를 하나 만들어도 될 것 같다. index가 필요한 이유는 이전 막대기가 무엇인지 알아야 하기 때문이니까! 그리고 elif로 () 레이저가 동작하는지 조건을 확인하는데, 그냥 "(" 조건 확인 후 else 구문에서 이전 값을 확인해도 될 수도?
🚨 문제 풀이 (시간 초과 났던 처음 문제 풀이)
# 시간 복잡도 O(N²)
arr = input()
stack = []
result = 0
for i, x in enumerate(arr):
if x == "(":
stack.append(1)
elif x == ")" and arr[i - 1] == "(":
stack = [s + 1 for s in stack] # 여기서 반복문이 한 번 더 동작
stack.pop()
else:
result += stack.pop()
print(result)
이 풀이는 각 막대기가 잘리는 수를 모두 stack에 담아두고 활용하는 방법이다. 레이저를 만나면 stack에 담긴 막대기 값을 1씩 더하는 반복문이 중간에 동작한다. 여기서 시간초과가 발생한 것 같다..
'💻 Computer Science > Algorithm' 카테고리의 다른 글
[Algorithm] 백준 1783 병든 나이트 | 그리디, 구현 (파이썬) (0) | 2025.04.11 |
---|---|
[Algorithm] 백준 2468 안전 영역 | BFS, DFS (파이썬) (0) | 2025.04.03 |