파이썬 알고리즘 033 | 쇠막대기 (스택) *****

Yunny.Log ·2021년 1월 12일
0

Algorithm

목록 보기
33/318
post-thumbnail

33. 쇠막대기

여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에
서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레
이저의 배치는 다음 조건을 만족한다.
• 쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에
놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
• 각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
• 레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다.
아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고,
점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.
이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할
수 있다.
1. 레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’ 으로 표현된다. 또한, 모든 ‘( ) ’는 반
드시 레이저를 표현한다.
2. 쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’ 로, 오른쪽 끝은 닫힌 괄호 ‘) ’ 로 표현된다.
위 예의 괄호 표현은 그림 위에 주어져 있다.
쇠막대기는 레이저에 의해 몇 개의 조각으로 잘려지는데, 위 예에서 가장 위에 있는 두 개의
쇠막대기는 각각 3개와 2개의 조각으로 잘려지고, 이와 같은 방식으로 주어진 쇠막대기들은
총 17개의 조각으로 잘려진다.
쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 주어졌을 때, 잘려진 쇠막대기 조각의 총
개수를 구하는 프로그램을 작성하시오.
▣ 입력설명
한 줄에 쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 공백없이 주어진다. 괄호 문자의
개수는 최대 100,000이다.
▣ 출력설명
잘려진 조각의 총 개수를 나타내는 정수를 한 줄에 출력한다.
▣ 입력예제 1
()(((()())(())()))(())
▣ 출력예제 1
17
▣ 입력예제 2
(((()(()()))(())()))(()())
▣ 출력예제 2
24
출처 : 한국정보올림피아드

<내 풀이>

도저히 어떻게 접근해야 하는지 모르겠다..
==> (), 즉 레이저가 등장하면 이 앞에 있던 쇠막대기들을 자르므로
그동안 앞에 있던 ( [쇠막대기 시작] 들의 개수를 더해준다
==>

=====> 선생님의 풀이를 듣고 구현해 본 코드


n=list(map(str, input()))
stack=[]
sum=0

for i in range(len(n)-1):
    if n[i]=="(" :
        stack.append(n[i])
        if n[i+1]==")" :
            stack.pop()
            sum+=len(stack)
    elif n[i]==")" :
        if n[i+1]==")" : 
            stack.pop()
            sum+=1
print(sum)

<풀이>

  • '(' 가 들어올 때는 stack에 append 해주면서 갯수를 갱신해줌 (cnt+=1)
  • 그런데 '('가 레이저의 '('인게 밝혀지면 얘는 pop시켜주고 지금까지 앞에 있던 애들을 더해준다

s=input()
stack=[]
cnt=0
for i in range(len(s)) :
    if s[i] =="(" : 
        stack.append(s[i])
    else :
        stack.pop()
        if s[i-1]=="(" : 
            cnt+=len(stack)
        else : 
            cnt+=1 #닫는 괄호와 레이저 사이에 조각 하나가 더 생성
print(cnt)

<다른 분의 풀이> - 스택 아니고

steel=input()
cnt=0
res=0
for i in range(len(steel)-1):
    if steel[i]=='(' and steel[i+1]==')':
        res+=cnt 		#그동안 열려있던 막대기들 다 갈랐음으로 막대기들 더해주기
    elif steel[i]=='(' and steel[i+1]=='(':
        cnt+=1 			#괄호가 열리면 막대기 생성 이므로 하나 더해서 세주기
    elif steel[i]==')' and steel[i+1]==')':
        res+=1 			#닫히면서 레이저랑 닫히는 사이에 하나 생성
        cnt-=1 			#막대기 닫혔으니 빼주어야 한다

<반성점>

  • 일단 스택이 아니고 그냥 일반 문제로 나왔어도 막혔을 문제라서 아쉬웠다
    문제를 창의적으로 해결하는 접근법이 아직 부족한 것 같다. 그대신 부족한 만큼 한번 개운 개념들, 유형들은 잊지 말고 계속 복습해나가면서 암기하고 써먹으면서 체화할 것이다

<배운 점>

  • 스택 문제로 접근할 때 이런 모양으로 생각하고 append, pop해주는 것으로 생각
  • a=input()
    이렇게만 하고 print(a)해도 ()(((()())(())()))(()) 이렇게 출력된다

0개의 댓글