아날로그 시계
어느날 문득 프로그래머스를 보는데 완료한 사람 48명에 정답률이 6% 인 문제가 보여 굉장히 흥미로워서 도전하게되었다. 흥미롭게 도전하게하고 흥미롭게 무너질 뻔 헀지만 어떻게든 풀긴풀었다.
문제 설명
문제는 간단하게 아날로그 시계를 구현하는 것이다. 특정 시간A 와 시간B가 주어지면 두 시간 사이에 시침과 분침이 만나는 횟수를 구하는 것이다.
흐름 파악
흐름 파악을 위해 꼬리에 꼬리를 무는 방식으로 접근하려한다.
시침, 분침, 초침의 각도는 어떻게 구할까?
- 초침은 60초에 한 바퀴를 돈다.
- 분침은 60분에 한 바퀴를 돈다.
- 시침은 12시간에 한 바퀴를 돈다.
당연히 원의 각도는 360도이므로 초침은 6도, 분침은 6도, 시침은 30도씩 움직인다.
문제 설명을 보면 0시 6분 0.501 초에 초침과 시침이 겹친다고 하는데 검사를 어떻게 해야해?
시간A ~ 시간B 까지 0.001 초 단위를 증가시키면서 검사한다면 86,400,000 반복문을 돌아야한다. 이는 시간 초과가 발생할 것이다.
24 * 60 * 60 * 1000 = 86400000
그래서 다른 방안으로는 1초씩 증가하면서 딱 겹치거나 지나갔는지 여부를 검사하는 것이 방법이 된다.
겹쳤는지 여부는 어떻게 구할까?
1초가 지났을 때 이전 분침, 시침의 각도보다 현재 시침 각도가 커지면 겹쳤던 것이다.
풀이 코드
분명 이 코드로 통과했지만 말끔하게 풀지 못했다. 문제를 풀고 다른 사람 풀이를 보면 언제나 훨씬 좋은 코드가 보이는데 배울거 배우고 가감없이 공유해서 성장을 위한 노력을 해야겠다.
코드 라인이 길어졌지만 크게 보면
- 1초 마다 시침, 분침, 초침 각도가 담긴 배열 생성
- 1초 마다 시침, 분침, 초침 각도를 이전 각도와 비교하여 카운트
def calc_clock_angle(h, m, s):
second_angle = 6 * s
minute_angle = 6 * m + (s / 10)
hour_angle = (30 * h + m * 0.5 + (s * (0.5 / 60))) % 360
return hour_angle, minute_angle, second_angle
def increase_s(cur_h, cur_m, cur_s):
cur_s += 1
if cur_s == 60:
cur_m += 1
cur_s = 0
if cur_m == 60:
cur_h += 1
cur_m = 0
return cur_h, cur_m, cur_s
def decrease_s(cur_h, cur_m, cur_s):
cur_s -= 1
if cur_s < 0:
cur_s = 59
cur_m -= 1
if cur_m < 0:
cur_m = 59
cur_h -= 1
if cur_h < 0:
cur_h = 23
return cur_h, cur_m, cur_s
def solution(h1, m1, s1, h2, m2, s2):
answer = 0
clock_angles = []
cur_h, cur_m, cur_s = h1, m1, s1
h2, m2, s2 = increase_s(h2, m2, s2)
while not (cur_h >= h2 and cur_m >= m2 and cur_s >= s2):
clock_angles.append(((cur_h % 12, cur_m, cur_s), calc_clock_angle(cur_h % 12, cur_m, cur_s)))
cur_h, cur_m, cur_s = increase_s(cur_h, cur_m, cur_s)
for i, angle_info in enumerate(clock_angles):
hms, angles = angle_info
h_angle, m_angle, s_angle = angles
if h_angle == 0 and m_angle == 0 and s_angle == 0:
answer += 1
continue
if m_angle == s_angle:
answer += 1
if i == 0:
continue
before_s_angle = clock_angles[i - 1][1][2]
if before_s_angle < h_angle < s_angle:
answer += 1
if hms[1] == 0 and hms[2] == 1:
answer -= 1
elif before_s_angle == 354 and before_s_angle < h_angle < 360:
answer += 1
if before_s_angle < m_angle < s_angle:
answer += 1
if hms[1] == 0 and hms[2] == 1:
answer -= 1
elif before_s_angle == 354 and before_s_angle < m_angle < 360:
answer += 1
return answer
print(solution(0, 0, 0, 23, 59, 59), 2852)
print(solution(23, 59, 58, 23, 59, 59), 0)
print(solution(23, 59, 57, 23, 59, 59), 0)
print(solution(0, 58, 59, 0, 59, 1), 0)
print(solution(0, 58, 58, 0, 59, 1), 1)
print(solution(12, 0, 0, 12, 1, 1), 2)
print(solution(12, 0, 0, 12, 0, 30), 1)
print(solution(0, 5, 59, 0, 7, 0), 2)
print(solution(0, 5, 30, 0, 7, 0), 2)
print(solution(12, 0, 58, 12, 1, 1), 1)
print(solution(12, 0, 0, 12, 0, 30), 1)
print(solution(12, 0, 0, 12, 0, 59), 1)
print(solution(11, 58, 0, 11, 59, 0), 2)
print(solution(12, 58, 00, 12, 59, 0), 2)
print(solution(12, 58, 00, 12, 59, 5), 3)
print(solution(12, 00, 1, 12, 1, 1), 1)
print(solution(12, 00, 1, 12, 1, 2), 2)
print(solution(0, 5, 59, 0, 7, 0), 2)
print(solution(0, 5, 30, 0, 7, 0), 2)
print(solution(0, 5, 30, 0, 7, 1), 3)
print(solution(0, 5, 30, 0, 7, 2), 3)
print(solution(0, 6, 1, 0, 6, 6), 0)
print(solution(11, 59, 59, 12, 0, 0), 1)
print(solution(12, 00, 0, 12, 0, 1), 1)
print(solution(12, 00, 1, 12, 0, 2), 0)
print(solution(12, 00, 1, 12, 0, 59), 0)
print(solution(12, 00, 1, 12, 1, 0), 0)
print(solution(11, 59, 59, 12, 0, 30), 1)
print(solution(0, 0, 0, 11, 59, 59), 1426)
print(solution(0, 0, 0, 0, 0, 30), 1)
print(solution(1, 5, 5, 1, 5, 6), 2)
print(solution(11, 59, 30, 12, 0, 0), 1)
print(solution(0, 5, 30, 0, 7, 0), 2)
print(solution(12, 0, 0, 12, 0, 30), 1)
print(solution(0, 6, 1, 0, 6, 6), 0)
print(solution(11, 59, 30, 12, 0, 0), 1)
print(solution(11, 58, 59, 11, 59, 0), 1)
print(solution(1, 5, 5, 1, 5, 6), 2)
print(solution(0, 0, 0, 23, 59, 59), 2852)
print(solution(0, 0, 0, 12, 0, 0), 1427)
print(solution(0, 0, 0, 0, 0, 1), 1)
print(solution(12, 0, 0, 23, 59, 59), 1426)