728x90
SMALL
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
- 이번에는 알고리즘 문제에 자주 등장하는 '스택 / 큐' 자료 구조를 이용한 문제들을 풀어보겠습니다!
스택은 뭐고 큐는 뭐죠?
- 우선 스택은 LIFO(Last-In, First-Out) 원칙을 따르는 선형 자료 구조입니다. 가장 마지막에 추가된 요소가 가장 먼저 빠져나온다는 것을 의미합니다.
- 스택은 재귀나 괄호 매칭 등의 문제에서 주로 적용되는 자료 구조입니다.
- 두 번째로 큐는 FIFO(First-In, First-Out) 원칙을 따르는 선형 구조입니다. 대기열을 관리하거나 BFS 문제에 주로 사용됩니다.
- 큐는 앞과 뒤 모두 접근이 가능하지만, 스택은 상단 요소에만 접근이 가능합니다.
- 이러한 특성들을 잘 기억해두셔서 아래 문제들에 적용하면 쉽게 풀 수 있을 것 같습니다!
Level 1 : 같은 숫자는 싫어
- 배열에서 연속적으로 중복되는 요소를 제거하여 다시금 배열을 반환하는 문제입니다.
- 스택의 원리를 이용하여 가장 마지막에 들어간 요소가 지금 추가할 요소와 중복이 되지 않는다면, 요소를 추가하는 방식으로 진행하였습니다.
def solution(arr):
stack = []
for e in arr:
if not stack or stack[-1] != e:
stack.append(e)
return stack
Level 2 : 기능 개발
- 배포 가능한 기능이 몇 개씩 묶일 수 있는지를 계산하는 문제입니다.
- 먼저, 각 작업에 대해 남은 작업 일수를 계산하기 위해서 math 모듈의 ceil() 함수를 사용하였습니다. 이유는 전에 작성하였던 Class 2 (달팽이는 올라가고 싶다 ~ 영화감독 숌) 포스팅에서의 '2869번: 달팽이는 올라가고 싶다' 문제와 유사하니 참고하시길 바랍니다.
- 첫 번째 기능이 완료되는 날을 설정한 후, 그 날이나 그 이후에 완료되는 기능들을 같은 배포 그룹으로 묶습니다.
- 더 이상 현재 배포 그룹에 속하지 않는 작업이 나오면 현재 그룹의 count를 answer 리스트에 추가한 뒤, 새로운 배포 그룹을 생성하기 시작합니다.
- 이 풀이에서는 첫 번째 기능이 완료되는 날을 기준으로 삼고, 해당 작업이 끝나면 큐의 다음 요소를 확인하는 식으로 큐의 특징을 사용하였습니다.
import math
def solution(progresses, speeds):
days_off = [math.ceil((100 - progress) / speed) for progress, speed in zip(progresses, speeds)]
answer = []
cnt = 1
first_day = days_off[0]
for day in days_off[1:]:
if day <= first_day:
cnt += 1
else:
answer.append(cnt)
cnt = 1
first_day = day
answer.append(cnt)
return answer
Level 2 : 올바른 괄호
- 올바른 괄호들을 구분하는 문제입니다.
- 이 문제도 스택 구조를 활용하여 열린 괄호 '('가 나올 때만 스택에 push하고, 닫힌 괄호 ')'가 나올 때는 스택에서 pop을 실행하여 올바른 괄호를 추출하도록 풀이하였습니다.
def solution(s):
pars = []
for char in s:
if char == '(':
pars.append(char)
elif not pars:
return False
else:
pars.pop()
return not pars
Level 2 : 프로세스
- 이 문제는 실제로도 프린터나 CPU의 작업 관리 같은 시스템 설계에서 접할 수 있는 문제입니다.
- 문제에 우선순위가 주어져있긴 하지만, 우선순위 큐로 접근하는 것이 아닌 일반 큐를 우선순위에 따라 재배치하는 로직으로 풀어내셔야 합니다.
- 운영체제는 매 순간마다 가장 높은 우선순위를 가지는 프로세스를 실행시킵니다. 만약 대기 중인 프로세스 중에서 우선순위가 더 높은 것이 존재한다면, 현재 프로세스는 다시 큐에 들어가게 됩니다.
def solution(priorities, location):
queue = [(p, idx) for idx, p in enumerate(priorities)]
answer = 0
while queue:
current = queue.pop(0)
if any(current[0] < other[0] for other in queue):
queue.append(current)
else:
answer += 1
if current[1] == location:
break
return answer
Level 2 : 다리를 지나는 트럭
- 각 트럭이 순차적으로 다리를 건널 때 걸리는 전체 최소 시간을 계산하는 문제입니다.
- 이번에는 파이썬에서 큐를 활용할 수 있는 방법 중 하나인 deque 라이브러리를 이용하여 구현하였습니다. deque 자료구조는 양방향 큐로, 양쪽 끝에서 요소를 빠르게 추가하거나 제거할 수 있기 때문에 시간 복잡도 면에서 큰 효율을 보여준답니다!
- 대기 중인 트럭이 있거나 다리 위에 트럭이 있는 동안 반복문을 실행시킵니다.
- 대기 중인 트럭이 있고, 다리 위의 현재 무게와 대기 중인 첫 번째 트럭의 무게 합이 다리의 최대 무게를 초과하지 않을 경우에 해당 트럭을 다리에 진입시킵니다.
- 위와 같은 상황으로 반복해주며 시간을 누적시켜주어 총 시간을 반환하는 로직입니다.
from collections import deque
def solution(bridge_length, weight, truck_weights):
time = 0
bridge = deque([0] * bridge_length)
bridge_weight = 0
truck_weights = deque(truck_weights)
while truck_weights or bridge_weight > 0:
time += 1
bridge_weight -= bridge.popleft()
if truck_weights and bridge_weight + truck_weights[0] <= weight:
truck = truck_weights.popleft()
bridge.append(truck)
bridge_weight += truck
else:
bridge.append(0)
return time
Level 2 : 주식가격
- 각 시점에서의 주식 가격에 대해 떨어지지 않는 시간을 계산하는 문제입니다.
- 먼저 결과 리스트를 각 가격이 떨어지지 않은 최대 기간으로 일단 초기화해둡니다.
- 빈 스택을 초기화해서 스택의 마지막 요소가 현재 가격보다 높은 경우에 스택에서 pop()를 실행해줍니다.
- 결과적으로 스택에서 나온 값을 결과 리스트에 넣어주고, 이를 prices 리스트의 길이만큼 반복해줍니다.
def solution(prices):
length = len(prices)
answer = [length-i-1 for i in range(length)]
stack = []
for idx in range(length):
while stack and prices[stack[-1]] > prices[idx]:
sec = stack.pop()
answer[sec] = idx - sec
stack.append(idx)
return answer
728x90
LIST
'알고리즘 문제 > 알고리즘 고득점 Kit' 카테고리의 다른 글
📙 가장 먼 노드 (0) | 2024.11.24 |
---|---|
📙 N으로 표현 (0) | 2024.11.19 |
📘📗📙 해시 (완주하지 못한 선수 ~ 베스트앨범) (1) | 2023.12.19 |