징검다리 건너기 문서의 문제 1 풀이 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""징검다리 건너기 (프로그래머스 64062) 풀이와 검증."""
import random
import time
from collections import deque
def solution(stones, k):
def ok(m): # m번째 친구도 건널 수 있나
run = 0
for s in stones:
if s < m: # m-1명이 지나가면 0 이하가 되는 돌
run += 1
if run >= k:
return False
else:
run = 0
return True
lo, hi = 1, max(stones)
while lo < hi: # 최대형 틀
mid = (lo + hi + 1) // 2
if ok(mid):
lo = mid
else:
hi = mid - 1
return lo
def by_window(stones, k):
"""길이 k인 창마다 가장 큰 돌 값을 구해, 그중 가장 작은 값을 돌려준다(덱으로 창 최댓값)."""
dq, best = deque(), None
for i, s in enumerate(stones):
while dq and stones[dq[-1]] <= s:
dq.pop()
dq.append(i)
if dq[0] <= i - k:
dq.popleft()
if i >= k - 1:
m = stones[dq[0]]
best = m if best is None else min(best, m)
return best
def by_walking(stones, k):
"""친구를 한 명씩 실제로 건너게 한다."""
st = stones[:]
n, people = len(st), 0
while True:
pos, steps = -1, []
while True:
nxt = next((j for j in range(pos + 1, n) if st[j] > 0), n)
if nxt - pos > k:
return people
if nxt == n:
break
steps.append(nxt)
pos = nxt
for j in steps:
st[j] -= 1
people += 1
if __name__ == "__main__":
ex = [2, 4, 5, 3, 2, 1, 4, 2, 5, 1]
assert solution(ex, 3) == 3
assert solution([2, 1, 3], 2) == by_walking([2, 1, 3], 2) == 2 # 1단계
# 6단계 추적
def longest_run(stones, m):
best = run = 0
for s in stones:
run = run + 1 if s < m else 0
best = max(best, run)
return best
assert [longest_run(ex, m) for m in (3, 4)] == [2, 3]
assert by_walking(ex, 3) == 3 == by_window(ex, 3)
# 무작위 비교
rng = random.Random(64062)
for _ in range(3000):
n = rng.randint(1, 10)
st = [rng.randint(1, 6) for _ in range(n)]
k = rng.randint(1, n)
a = solution(st, k)
assert a == by_walking(st, k) == by_window(st, k), (st, k)
# 효율성: 돌 20만 개, 값 2억까지
big = [rng.randint(1, 200_000_000) for _ in range(200_000)]
t0 = time.perf_counter()
r = solution(big, 1000)
tt = time.perf_counter() - t0
assert r == by_window(big, 1000) and tt < 10, tt
same = [200_000_000] * 200_000 # 판정이 늘 끝까지 훑는 입력
t0 = time.perf_counter()
assert solution(same, 200_000) == 200_000_000
tt = max(tt, time.perf_counter() - t0)
print(f"200k stones: {tt:.2f}s")
print("ALL CHECKS PASSED")