풀이
시작하는 시간부터 끝나는 시간동안 초침이 몇 번 분침과 시침을 지나치는지에 대한 문제다.
(1)
시작시간과 끝시간 사이를 간격에서 횟수를 구하는 것 보다는 (0시0분0초~끝나는 시간동안 마주친 횟수)에 (0시0분0초~시작하는 시간동안 마주친 횟수)를 빼는 방법을 이용하면 문제를 훨씬 단순하게 해결할 수 있다.
주의할 점은 이렇게 차이를 계산하는 방법은 시작시간 자체가 알람이 울리는 시간이라면 이 횟수까지 제외해버린다. 때문에 마지막에 현재 시간 또한 알람이 울릴 수 있는지 체크해서 횟수에 반영해줘야 한다.
초침이 시계 한 바퀴를 도는 시간은 60초
분침이 시계 한 바퀴를 도는 시간은 60분 -> 3,600초
시침이 시계 한 바퀴를 도는 시간은 12시간 -> 43,200초
분침이 한 바퀴 도는 동안 초침은 60(=3600초/60초)바퀴를 돈다
분침이 한 바퀴 돌 동안(3600초) 초침과 59번 마주친다. 60번이 아닌 이유는 분침도 이 시간동안 제자리에만 있는 게 아니기 때문!
즉, 분침과 만나서 울리는 알람은 3600초 동안 59번 울리며, 3600/59 초마다 1회 울린다.
시침이 한 바퀴 도는 동안 초침은 720(=43200초/60초)바퀴를 돈다
== 시침이 한 바퀴 돌 동안(43200초) 초침과 719번 마주친다. 720번이 아닌 이유는 마찬가지로 시침 또한 움직이고 있기 때문!
즉 분침과 만나서 울리는 알람은 43200초 동안 719번 울리며, 43200/719 초마다 1회 울린다.
(2)
문제를 "n초 동안 몇 번 울리는가?"로 바꿔서 생각해 볼 수 있겠다.
분침의 경우는 n % (3600/59) 번 마주치고
시침의 경우는 n % (43200/719) 번 마주친다
(이 식이 이해가 안된다면 10초마다 알람이 울린다고 했을 때 1분동안 몇 번 울리는 지 생각해보면 된다. 1분 / 10초 = 6번 이라고 계산하듯이 n초에 알람 1회가 울리는 초를 나누면 된다)
(3)
예외 사항이 있다. 분침과 시침이 겹쳐있는 경우다. 이 때는 분침과 시침이 각각 겹쳐도 알람은 1번만 울려야한다. 분침과 시침, 그리고 초침이 모두 겹치는 경우는 12시 정각 뿐이다. 우리는 (1)에서 0시0분0초에 시작하기로 했기 때문에 00시 정각과 12시 정각 두 시각에 대해 고려해야한다.
n초가 43200초(12시0분0초)보다 작다면 00시만 고려해서 1회, 크다면 12시까지 포함해 2회가 중복된 셈이니 이 횟수만큼 빼줘야 한다.
코드
import java.util.*;
class Solution {
public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
int answer = -1;
int startSec = parseToSec(h1, m1, s1);
int endSec = parseToSec(h2, m2, s2);
// (1)
answer = countAlrams(endSec) - countAlrams(startSec);
answer += alramNow(startSec) ? 1 : 0;
return answer;
}
private int parseToSec(int hour, int minute, int second) {
return hour * 60 * 60 + minute * 60 + second;
}
private int countAlrams(int seconds) {
// (2)
int minuteAlrams = seconds * 59 / 3600;
int hourAlrams = seconds * 719 / 43200;
// (3)
int duplicatedAlrams = 43200 <= seconds ? 2 : 1;
return minuteAlrams + hourAlrams - duplicatedAlrams;
}
private boolean alramNow(int seconds) {
return seconds * 59 / 3600 == 0 || seconds * 719 % 43200 == 0;
}
}
도움 받은 경로
'Tech > Problem Solving' 카테고리의 다른 글
[프로그래머스] 2024 KAKAO WINTER INTERNSHIP - 도넛과 막대 그래프 (Java) (0) | 2024.03.10 |
---|---|
[프로그래머스] 2023 KAKAO BLIND RECRUITMENT - 택배 배달과 수거하기 (Java) (0) | 2024.03.10 |
[알고리즘] Java로 정렬 알고리즘 구현해보기 (0) | 2022.03.02 |
[프로그래머스] 2021 Dev-Matching: 웹 백엔드 개발자(상반기) - 헤비 유저가 소유한 장소 (MySQL) (0) | 2022.03.01 |
[프로그래머스] Summer/Winter Coding(2019) - 우유와 요거트가 담긴 장바구니 (MySQL) (0) | 2022.03.01 |