[python] 스택/큐

이희진·2022년 9월 16일
0

스택

스택은 한쪽 끝에서만 자료의 삽입(Push)과 삭제(Pop)가 일어나는 자료구조로 파이썬에서는 리스트(List)를 활용해 스택을 구현하기 때문에 스택을 위한 모듈이 따로 필요하지 않다.

# 스택

# 리스트를 활용해 스택을 생성
stack = []

# 자료의 삽입(Push)
# append() 메서드를 활용
stack.append(4) # [4]
stack.append(1) # [4, 1]
stack.append(3) # [4, 1, 3]

# 자료의 삭제(Pop)
# pop() 메서드를 활용
stack.pop() # 3
stack.pop() # 1
stack.pop() # 4

stack # []

# 스택의 최상단 자료의 확인
# 리스트 인덱싱[-1]을 활용한다.
stack.append(1) # [1]
stack[-1] # 1
stack.append(3) # [1, 3]
stack[-1] # 3

# 스택이 비어있는지 확인
# 조건문을 활용해 스택이 비어있는지 확인 할 수 있다.
if stack:
    # 스택이 비어있지 않은 경우
    pass
else:
    # 스택이 비어있는 경우
    pass
    
# 스택의 크기 확인
# len(stack)으로 확인
stack = [1, 2, 3, 4] # [1, 2, 3, 4]
len(stack) # 4
stack.pop() # 4
len(stack) # 3

큐는 먼저 집어넣은 자료가 먼저 나오는 자료형을 말하며, 일반적으로 우리가 볼 수 있는 표를 사기 위한 줄을 예시로 들 수 있다. 파이썬에는 queue라는 내부 라이브러리도 있지만, queue도 내부적으로는 collections.deque로 queue를 관리하기 때문에 collections.deque를 사용하는 것을 추천한다.

# 큐
from collections import deque

# deque 생성
queue = deque()

# append
# 오른쪽에 데이터 추가
queue.append(3) # deque([3])
queue.append(5) # deque([3, 5])
queue.append(7) # deque([3, 5, 7])

# appendleft
# 왼쪽에 데이터 추가
queue.appendleft(2) # deque([2, 3, 5, 7])
queue.appendleft(4) # deque([4, 2, 3, 5, 7])

# pop
# 오른쪽에서 데이터 삭제
queue.pop() # 7
queue.pop() # 5

# popleft
# 왼쪽에서 데이터 삭제
queue.popleft() # 4
queue.popleft() # 2

queue # deque([3)

Deque는 덱이라고 불리는 자료구조인데 일반 큐와 달리 앞과 뒤 모두에서 데이터의 삽입과 삭제가 일어난다. 스택과 큐의 일반화된 경우라고 볼 수 있는데 연결 리스트로 구현되어있어 삽입과 삭제가 O(1) 안에 끝나 매우 빠르다.

주의할 점이 파이썬 list를 활용해 큐를 만들면서 아래와 같이 insert를 활용해 자료를 추가하는 경우가 있는데, 이 경우 삽입할 때 list 내부에 있는 모든 원소를 한 칸씩 이동시켜야 하기 때문에 O(n)의 시간 복잡도를 가진다. 따라서 경우에 따라서는 시간 초과가 발생할 수 있다.

문제 1 - 올바른 괄호

괄호가 바르게 짝지어졌다는 것은 '(' 문자로 열렸으면 반드시 짝지어서 ')' 문자로 닫혀야 한다는 뜻입니다.
예를 들어
"()()" 또는 "(())()" 는 올바른 괄호입니다.
")()(" 또는 "(()(" 는 올바르지 않은 괄호입니다.

'(' 또는 ')' 로만 이루어진 문자열 s가 주어졌을 때, 문자열 s가 올바른 괄호이면 true를 return 하고, 올바르지 않은 괄호이면 false를 return 하는 solution 함수를 완성해 주세요.

def is_pair(s):
    st = list()
    for c in s:
        if c == '(':
            st.append(c)

        if c == ')':
            try:
                st.pop()
            except IndexError:
                return False

    return len(st) == 0

문제 2 - 기능개발

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.

또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

from collections import deque
def solution(progresses, speeds):
    p = deque(progresses)
    s = deque(speeds)
    answer = []
    count = 0
    while p:
        for i in range(0, len(p)):
            p[i] += s[i]
        while p and p[0] >= 100:
            count += 1
            p.popleft()
            s.popleft()
        if count > 0:
            answer.append(count)
        count = 0
    return answer

문제 3 - 프린터

일반적인 프린터는 인쇄 요청이 들어온 순서대로 인쇄합니다. 그렇기 때문에 중요한 문서가 나중에 인쇄될 수 있습니다. 이런 문제를 보완하기 위해 중요도가 높은 문서를 먼저 인쇄하는 프린터를 개발했습니다. 이 새롭게 개발한 프린터는 아래와 같은 방식으로 인쇄 작업을 수행합니다.

  1. 인쇄 대기목록의 가장 앞에 있는 문서(J)를 대기목록에서 꺼냅니다.
  2. 나머지 인쇄 대기목록에서 J보다 중요도가 높은 문서가 한 개라도 존재하면 J를 대기목록의 가장 마지막에 넣습니다.
  3. 그렇지 않으면 J를 인쇄합니다.
    예를 들어, 4개의 문서(A, B, C, D)가 순서대로 인쇄 대기목록에 있고 중요도가 2 1 3 2 라면 C D A B 순으로 인쇄하게 됩니다.

내가 인쇄를 요청한 문서가 몇 번째로 인쇄되는지 알고 싶습니다. 위의 예에서 C는 1번째로, A는 3번째로 인쇄됩니다.

현재 대기목록에 있는 문서의 중요도가 순서대로 담긴 배열 priorities와 내가 인쇄를 요청한 문서가 현재 대기목록의 어떤 위치에 있는지를 알려주는 location이 매개변수로 주어질 때, 내가 인쇄를 요청한 문서가 몇 번째로 인쇄되는지 return 하도록 solution 함수를 작성해주세요.

from collections import deque
def solution(priorities, location):
    count = 0
    ps = deque(priorities)
    while ps:
        count += 1
        top_p = max(ps)
        top_index = ps.index(top_p)
        if top_index == location:
            break
        for i in range(0, top_index):
            tmp = ps.popleft()
            ps.append(tmp)
            if location == 0:
                location = len(ps) - 1
            else: 
                location -= 1
        ps.popleft() 
        location -= 1
    answer = count
    return answer

0개의 댓글