표 편집 문서의 문제 1 풀이 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""표 편집 (프로그래머스 81303) 풀이와 검증."""
import bisect
import random
import time
def solution(n, k, cmd):
prev = [i - 1 for i in range(n)]
nxt = [i + 1 for i in range(n)]
removed = []
cur = k
for c in cmd:
if c[0] == "U":
for _ in range(int(c[2:])):
cur = prev[cur]
elif c[0] == "D":
for _ in range(int(c[2:])):
cur = nxt[cur]
elif c[0] == "C":
removed.append(cur)
p, q = prev[cur], nxt[cur]
if p != -1:
nxt[p] = q
if q != n:
prev[q] = p
cur = q if q != n else p # 마지막 행이면 위로
else: # Z
x = removed.pop()
p, q = prev[x], nxt[x]
if p != -1:
nxt[p] = x
if q != n:
prev[q] = x
ans = ["O"] * n
for x in removed:
ans[x] = "X"
return "".join(ans)
def by_list(n, k, cmd, log=None):
"""살아 있는 행 번호를 리스트로 들고 문제 그대로 흉내 낸다."""
table, stack, cur = list(range(n)), [], k # cur은 선택된 행의 원래 번호
for c in cmd:
i = table.index(cur)
if c[0] == "U":
cur = table[i - int(c[2:])]
elif c[0] == "D":
cur = table[i + int(c[2:])]
elif c[0] == "C":
stack.append(table.pop(i))
cur = table[i] if i < len(table) else table[i - 1]
else:
bisect.insort(table, stack.pop())
if log is not None:
log.append((c, cur, "".join("O" if r in table else "X" for r in range(n)), list(stack)))
return "".join("O" if r in set(table) else "X" for r in range(n))
if __name__ == "__main__":
c1 = ["D 2", "C", "U 3", "C", "D 4", "C", "U 2", "Z", "Z"]
assert solution(8, 2, c1) == "OOOOXOOO"
assert solution(8, 2, c1 + ["U 1", "C"]) == "OOXOXOOO"
# 1단계 예
l1 = []
assert solution(5, 2, ["C", "C", "Z"]) == by_list(5, 2, ["C", "C", "Z"], l1) == "OOXOO"
assert [cur for _, cur, _, _ in l1] == [3, 4, 4]
# 6단계 추적
log = []
by_list(8, 2, c1, log)
assert log == [
("D 2", 4, "OOOOOOOO", []),
("C", 5, "OOOOXOOO", [4]),
("U 3", 1, "OOOOXOOO", [4]),
("C", 2, "OXOOXOOO", [4, 1]),
("D 4", 7, "OXOOXOOO", [4, 1]),
("C", 6, "OXOOXOOX", [4, 1, 7]),
("U 2", 3, "OXOOXOOX", [4, 1, 7]),
("Z", 3, "OXOOXOOO", [4, 1]),
("Z", 3, "OOOOXOOO", [4]),
], log
# 무작위 비교
rng = random.Random(81303)
for _ in range(3000):
n = rng.randint(5, 12)
k = rng.randrange(n)
table, stack, cur, cmd = list(range(n)), [], k, []
for _ in range(rng.randint(1, 25)):
i = table.index(cur)
r = rng.random()
if r < 0.25 and i > 0:
x = rng.randint(1, i); cmd.append(f"U {x}"); cur = table[i - x]
elif r < 0.5 and i < len(table) - 1:
x = rng.randint(1, len(table) - 1 - i); cmd.append(f"D {x}"); cur = table[i + x]
elif r < 0.8 and len(table) > 1:
cmd.append("C"); stack.append(table.pop(i))
cur = table[i] if i < len(table) else table[i - 1]
elif stack:
cmd.append("Z"); bisect.insort(table, stack.pop())
assert solution(n, k, cmd) == by_list(n, k, cmd), (n, k, cmd)
# 효율성: 행 100만 개, 명령 20만 개(삭제·복구 위주, 이동 합 100만)
n = 1_000_000
big = []
for i in range(200_000):
big.append("C" if i % 4 < 2 else ("Z" if i % 4 == 2 else "D 5"))
t0 = time.perf_counter()
solution(n, n // 2, big)
t = time.perf_counter() - t0
assert t < 5, t
print(f"n=1e6, cmd=2e5: {t:.2f}s")
print("ALL CHECKS PASSED")