https://school.programmers.co.kr/learn/courses/30/lessons/250135
주어진 시작 시간(h1 m1 s1
)부터 주어진 종료 시간(h2 m2 s2
)까지 시침과 초침, 분침과 초침이 겹치는 횟수를 구하라
h1, m1, s1 = 0, 5, 30
h2, m2, s2 = 0, 7, 0
매 초마다 '초' 가 '분' 혹은 '시' 와 같아지는 경우를 세는 경우라면 매우 간단하게 해결할 수 있다.(디지털 시계)
ex)
def solution(h1, m1, s1, h2, m2, s2):
count = 0
while (True):
# 60초가 되면 분 올려주기
if s1 >= 60:
m1 += 1
s1 = 0
# 60분이 되면 시 올려주기
if m1 >= 60:
h1 += 1
m1 = 0
#현재 시간이 목표 시간이 되면 종료
if h1 == h2 and m1 == m2 and s1 == s2:
break
if s1 == m1 or s1 == h1 % 12:
count += 1
s1 += 1
return count
하지만 이 문제는 아날로그 시계로 초침이 이동할 때마다 분침과 시침이 미세하게 조금씩 움직이는 경우이다.
이런 경우라면 초마다 초침이 시침/분침을 지났는지만 검사하면 된다.
그러기 위해서 초마다 시침, 분침, 초침이 움직이는 각도를 구해서 초침이 시침/분침을 지났는지만 확인해주면 된다.
def solution(h1, m1, s1, h2, m2, s2):
answer = 0
# 시작시간과 끝시간을 초단위로 변환
startTime = h1 * 3600 + m1 * 60 + s1
endTime = h2 * 3600 + m2 * 60 + s2
# next기준으로 계산할거니 포함되지 않는 시작시간 00시, 12시 미리 카운팅
if startTime == 0 * 3600 or startTime == 12 * 3600:
answer += 1
while startTime < endTime:
# 시침 1시간 = 30도 -> 1초에 30/3600도 즉, 1/120도 이동
# 분침 1분 = 6도 -> 1초에 6/60도 즉, 1/10도 이동
# 초침 1초 = 6도 -> 1초에 6도 이동
hCurAngle = startTime / 120 % 360
mCurAngle = startTime / 10 % 360
sCurAngle = startTime * 6 % 360
# 다음 위치가 360도가 아닌 0도로 계산되어 카운팅에 포함되지 않는 경우 방지
# 이동했을 때 지나쳤거나 같아졌는지를 비교하는 것이므로 현재위치는 해줄 필요없음
hNextAngle = 360 if (startTime + 1) / 120 % 360 == 0 else (startTime + 1) / 120 % 360
mNextAngle = 360 if (startTime + 1) / 10 % 360 == 0 else (startTime + 1) / 10 % 360
sNextAngle = 360 if (startTime + 1) * 6 % 360 == 0 else (startTime + 1) * 6 % 360
if sCurAngle < hCurAngle and sNextAngle >= hNextAngle:
answer += 1
if sCurAngle < mCurAngle and sNextAngle >= mNextAngle:
answer += 1
# 시침/분침과 동시에 겹쳤을 때 중복카운팅 제외
if sNextAngle == hNextAngle and hNextAngle == mNextAngle:
answer -= 1
startTime += 1
return answer
O(endTime - startTime)
검색해보지 않고는 풀지 못했음
lv2 문제라기엔 생각보다 어려움. 문제의 접근 방식은 빠르게 찾았으나, 그걸 어떤 방식으로 구현해야 할 지 떠오르지 않았음.
시계문제에서 각도를 고려하는 방법도 하나의 방법이라는 것을 깨달았음.