2026년 1월 25일

[프로그래머스] 지게차와 크레인 (Python)

 

문제 설명

  • 물류 창고에서 지게차크레인을 이용해 출고할 컨테이너를 다 꺼냈을 때, 남은 컨테이너의 수를 구하는 문제
 

예제 입력/출력

storage
requests
result
["AZWQY", "CAABX", "BBDDA", "ACACA"]
["A", "BB", "A"]
11
["HAH", "HBH", "HHH", "HAH", "HBH"]
["C", "B", "B", "B", "B", "H"]
4
 

제약 조건

  • 2 ≤ storage 의 길이 ≤ 50
    • 2 ≤ storage[0] 의 길이 ≤ 50
  • 1 ≤ requests 의 길이 ≤ 100
    • requests[i]의 길이가 1: 지게차를 이용한 출고 요청
    • requests[i]의 길이가 2: 크레인을 이용한 출고 요청
 

문제 풀이

1️⃣ 출고 방법 파악

  • 출고 방법에는 크게 지게차와 크레인이 존재한다.
  • 크레인의 경우 컨테이너의 위치와 관계 없이 출고가 가능하다.
  • 반면에 지게차의 경우 컨테이너의 위치가 외부와 연결돼있어야 출고가 가능하다.
 

2️⃣ 전체 흐름 (메인 함수)

  • 먼저 storage를 2차워 배열로 변환해 grid에 저장한다.
  • 메인 함수에서는 요청을 순차적으로 처리하면서, 요청 길이에 따라 지게차 혹은 크레인을 선택해 실행한다.
  • 모든 요청을 처리한 후에는 남은 컨테이너 개수를 반환한다.
 
def solution(storage, requests): grid = [list(row) for row in storage] for req in requests: if len(req) == 1: forklift(grid, req) else: crane(grid, req[0]) # 남은 컨테이너 개수 count = 0 for col in grid: for row in col: if row != '.': count += 1 return count
 

3️⃣ 크레인

  • 크레인은 2차원 배열을 모두 순회하며 내가 찾고자 하는 컨테이너인지를 확인하고 꺼낸다.
  • 이 경우 시간 복잡도는 으로, 최악의 경우 2,500번의 탐색이 필요하다.
 
def crane(grid, target): n, m = len(grid), len(grid[0]) for i in range(n): for j in range(m): if grid[i][j] == target: grid[i][j] = '.'
 

4️⃣ 지게차

  • 지게차는 조금 까다로운게 내가 꺼내고자 하는 컨테이너가 외부와 연결돼있어야 한다.
  • 여기서 외부와 연결돼있는다는 의미는 다음과 같다.
      1. 2차원 배열의 가장자리에 해당 컨테이너가 위치한 경우
      1. 가장자리에 위치해 있지는 않지만, 인접한 방향 중 하나라도 외부와 이어진 통로(.)가 존재하는 경우
  • 이를 판단하기 위해,
    • 배열의 가장자리부터 시작하여 . 칸만을 따라 BFS로 외부와 이어진 통로인지 판별하고,
    • 이후, 제거 대상 컨테이너가 외부와 이어진 통로와 인접해 있는지를 확인하여 제거 여부를 결정한다.
 
# 외부 통로와 연결돼있는지 체크용 visited = [[False]*m for _ in range(n)] q = deque() # 테두리에 있는 '.'을 시작으로 외부와 연결돼있는지 체크 시작 (bfs) for i in range(n): for j in range(m): if i == 0 or i == n-1 or j == 0 or j == m-1: if grid[i][j] == '.': visited[i][j] = True q.append((i, j))
  • 테두리에 있는 . 을 시작으로 외부와 연결돼있는지 체크를 시작한다.
  • bfs 를 위해 가장자리에 . 이 있다면 탐색을 이어나가기 위해 큐에 추가해준다.
 
# 외부와 연결된 모든 '.' 영역 탐색 (내부에 갇힌 '.'은 제외) dirs = [(1,0), (-1,0), (0,1), (0,-1)] while q: x, y = q.popleft() for dx, dy in dirs: nx, ny = x + dx, y + dy if 0 <= nx < n and 0 <= ny < m: if not visited[nx][ny] and grid[nx][ny] == '.': visited[nx][ny] = True q.append((nx, ny))
  • 큐가 빌 때까지 외부와 연결된 모든 . 영역을 탐색한다.
 
# 외부와 맞닿아있는 target 컨테이너만 제거 for i in range(n): for j in range(m): if grid[i][j] == target: for dx, dy in dirs: ni, nj = i + dx, j + dy # 가장자리 밖이거나, 외부와 연결된 통로와 맞닿아 있는 경우 if not (0 <= ni < n and 0 <= nj < m) or visited[ni][nj]: grid[i][j] = '.' break
  • BFS 를 통해 visited 로 외부와 연결된 통로(.) 영역을 모두 표시해두었기 때문에, 제거 대상 컨테이너(target)가 해당 외부 통로와 인접해 있는지만 확인하면 된다.
  • 컨테이너의 상하좌우 중 하나라도 가장자리 바깥이거나, visitedTrue인 위치가 존재한다면 외부에서 지게차로 접근이 가능한 상태이므로 제거가 가능하다.
  • 지게차도 크레인과 마찬가지로 최악의 경우 전체 탐색을 하기에 시간 복잡도가 소요된다.
 

풀이 코드

notion image
from collections import deque def crane(grid, target): n, m = len(grid), len(grid[0]) for i in range(n): for j in range(m): if grid[i][j] == target: grid[i][j] = '.' def forklift(grid, target): n, m = len(grid), len(grid[0]) # 외부 통로와 연결돼있는지 체크용 visited = [[False]*m for _ in range(n)] q = deque() # 테두리에 있는 '.'을 시작으로 외부와 연결돼있는지 체크 시작 (bfs) for i in range(n): for j in range(m): if i == 0 or i == n-1 or j == 0 or j == m-1: if grid[i][j] == '.': visited[i][j] = True q.append((i, j)) # 외부와 연결된 모든 '.' 영역 탐색 (내부에 갇힌 '.'은 제외) dirs = [(1,0), (-1,0), (0,1), (0,-1)] while q: x, y = q.popleft() for dx, dy in dirs: nx, ny = x + dx, y + dy if 0 <= nx < n and 0 <= ny < m: if not visited[nx][ny] and grid[nx][ny] == '.': visited[nx][ny] = True q.append((nx, ny)) # 외부와 맞닿아있는 target 컨테이너만 제거 for i in range(n): for j in range(m): if grid[i][j] == target: for dx, dy in dirs: ni, nj = i + dx, j + dy # 이미 외부이거나, 외부와 통로가 이어져있는 경우 if not (0 <= ni < n and 0 <= nj < m) or visited[ni][nj]: grid[i][j] = '.' break def solution(storage, requests): grid = [list(row) for row in storage] for req in requests: if len(req) == 1: forklift(grid, req) else: crane(grid, req[0]) # 남은 컨테이너 개수 count = 0 for col in grid: for row in col: if row != '.': count += 1 return count