문제 보기 · Level 2 · 2018 KAKAO BLIND RECRUITMENT (1차) · 정답률 59% · 푼 사람 15,189명 (2026-09-30 기준)1
문제
m×n 판에 블록이 대문자로 놓여 있다. 같은 블록 네 개가 2×2로 붙어 있으면 지운다. 그런 2×2가 여러 개면 겹치더라도 한꺼번에 지운다. 지운 뒤 위 블록이 아래로 떨어지고, 다시 지울 수 있으면 되풀이한다. 지워진 블록의 총수를 돌려준다.
- 2 ≤ m, n ≤ 30
풀이
막히면 한 단계씩 펼친다.
필요한 개념
구현과 시뮬레이션: “찾기 → 한꺼번에 지우기 → 떨어뜨리기”를 더 지울 게 없을 때까지 되풀이한다. 한꺼번에 바뀌는 규칙은 표시해 두었다가 나중에 바꾼다.
1단계 · 작은 예로 손으로 풀기
A A B
A A B
C C B
- 2×2를 모두 본다. 왼쪽 위 (A A / A A)만 같다 → 4칸 지움
- 지운 칸을 빈칸(.)으로:
. . B . . B C C B - 떨어뜨린다: 왼쪽 두 열은 C가 이미 바닥에 있어 그대로다
- 다시 2×2를 보면 같은 것이 없다 → 끝
답은 4다. 두 2×2가 한 칸을 함께 쓰면(겹치면) 그 칸은 한 번만 센다. 예를 들어 A가 2×3으로 붙어 있으면 2×2가 두 개지만 지워지는 블록은 6개다. 겹친 2칸을 한 번 빼는 포함-배제 원리의 셈 4 + 4 − 2 = 6과 같다.
2단계 · 가장 단순한 방법과 그 속도
한 판을 볼 때 2×2는 최대 29 × 29 = 841개다. 판을 한 번 볼 때마다 적어도 4개가 지워지니 되풀이는 많아야 900 ÷ 4 = 225번이다. 모두 20만 번 정도라 넉넉하다. 이 문제는 규칙을 정확히 옮기는 문제다.
3단계 · 핵심 아이디어
- 한꺼번에 지우기: 2×2를 찾는 동안에는 판을 고치지 않는다. 지울 칸의 좌표를 집합에 모은다. 집합이라 겹친 칸도 한 번만 들어간다. 다 찾은 뒤 한 번에 지운다.
- 떨어뜨리기: 열마다 빈칸이 아닌 블록만 위에서 아래 순서로 모은다. 그 열을 모두 비우고, 모은 블록을 바닥부터 다시 쌓는다.
- 끝내기: 지울 칸이 하나도 없으면 멈추고 지금까지 센 수를 돌려준다.
4단계 · 코드 흐름
- 문자열 줄들을 고칠 수 있게 글자 리스트의 리스트로 바꾼다.
- 되풀이:
- 모든 2×2의 왼쪽 위 (r, c)마다 네 칸이 같고 빈칸이 아니면 네 좌표를 집합에 넣는다.
- 집합이 비었으면 합계를 돌려준다.
- 합계에 집합 크기를 더하고, 그 칸들을 빈칸으로 만든다.
- 열마다 블록을 바닥으로 떨어뜨린다.
5단계 · 파이썬 코드
def solution(m, n, board):
b = [list(row) for row in board] # 고칠 수 있는 2차원 리스트
total = 0
while True:
hit = set()
for r in range(m - 1):
for c in range(n - 1):
x = b[r][c]
if x != "." and x == b[r][c + 1] == b[r + 1][c] == b[r + 1][c + 1]:
hit |= {(r, c), (r, c + 1), (r + 1, c), (r + 1, c + 1)}
if not hit:
return total
total += len(hit)
for r, c in hit:
b[r][c] = "."
for c in range(n): # 열마다 떨어뜨리기
blocks = [b[r][c] for r in range(m) if b[r][c] != "."] # 위→아래 순서
for r in range(m):
b[r][c] = "."
for i, x in enumerate(reversed(blocks)): # 바닥부터 쌓기
b[m - 1 - i][c] = x
list(row): 문자열"CCBDE"를['C', 'C', 'B', 'D', 'E']로 바꾼다. 문자열은 칸을 고칠 수 없기 때문이다.x == a == b == c: 네 값이 모두 같은지 한 줄로 비교한다.hit |= {…}: 집합에 네 좌표를 더한다(합집합).reversed(blocks): 맨 아래 블록부터 꺼내 바닥(m - 1)부터 채운다.
6단계 · 실행 추적
m = 4, n = 5, board = [“CCBDE”, “AAADE”, “AAABF”, “CCBBF”]
| 되풀이 | 찾은 2×2 | 지운 수 | 합계 |
|---|---|---|---|
| 1 | A 2×3 덩어리 안의 2×2 두 개(겹침) | 6 | 6 |
| 2 | 떨어진 뒤 생긴 2×2 | 8 | 14 |
| 3 | 없음 | 14 |
답은 14다. 되풀이 1에서 A 여섯 칸은 2×2 두 개가 가운데 두 칸을 함께 쓰지만 한 번씩만 셌다.
7단계 · 복잡도와 흔한 실수
되풀이 R번마다 판 전체(m·n)를 보니 \(O(R \cdot mn)\)이고, R ≤ mn / 4다.
- 찾으면서 바로 지워서, 같은 차례에 지워져야 할 다른 2×2를 놓친다.
- 겹친 칸을 두 번 센다.
- 빈칸끼리 2×2가 같다고 보고 지운다(빈칸 검사
x != "."). - 위아래를 거꾸로 떨어뜨린다.
-
프로그래머스 스쿨, “[1차] 프렌즈4블록” (https://school.programmers.co.kr/learn/courses/30/lessons/17679), 2026-09-30 조회. ↩