알고리즘
[PCCP 기출 3번] 아날로그 시계
moongi
2025. 6. 6. 15:10
728x90
반응형
https://school.programmers.co.kr/learn/courses/30/lessons/250135
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 유형
- 시뮬레이션
문제 난이도
- Lev2
문제 분석
아이디어를 생각하면 코드 자체는 어렵지 않았지만, 아이디어는 도출해냈지만, 정확하게 어떻게 풀어야겠다고 생각하지 못해, 다른 분의 아이디어를 참고하였다.
특정 시점부터 종료 시점까지 초침과 시침 / 분침이 만나는 횟수를 구하는 문제이다.
만약 같은 시점에 동일하게 시침과 분침이 모두 만나는 경우는 한 번만 카운팅하도록 한다.
우선 1초마다 시각이 변화할 때의 각도를 먼저 구해준다.
1. 시각이 변화하는 각도 : 1시간 -> 30도, 분당 0.5도, 초당 1/120도
2. 분침이 변화하는 각도 : 분당 -> 6도, 초당 0.1도
3. 시침이 변화하는 각도 : 초당 -> 6도
hDegree : 시침의 각도, mDegree: 분침의 각도, sDegree: 초침의 각도
초침과 시침 / 분침이 만나는 경우
1. 1초가 지나기 전 hDegree > sDegree, 1초가 지난 후, hDegree < sDegree 인 경우 -> 시침과 초침
2. 1초가 지나기 전 mDegree > sDegree, 1초가 지난 후, mDegree < sDegree 인 경우 -> 분침과 초침
초침과 시침, 분침이 모두 같은 시점에 만나는 경우(validate)
-> 1초가 지난 시점에 분침과 시침 모두 겹쳐진 경우, 중복이므로, 하나로만 카운팅을 계산한다.
코드 분석
현재 시각에 대한 시침, 분침, 초침의 각도를 구하는 메소드이다. 주의할 점은 모든 침들은 소수점을 포함하므로 형 변환에 주의하도록 한다.
(ex. 1/120은 int형 / int형이므로 int형을 반환한다. 따라서 0이 나오는데, 실수하지 않기 위해 double형 / int형으로 작성하거나 (double)과 같이 타입 명시를 해준다.
static void calculateDegree(int h, int m, int s) {
hDegree = (h % 12) * 30.0 + m * 0.5 + s * (1.0 / 120);
mDegree = m * 6.0 + s * 0.1;
sDegree = s * 6.0;
}
현재 시점과 1초 지난 시점을 나눠서 진행한다.
조건문은 차례대로
1. 시침에 대한 비교
2. 분침에 대한 비교
3. 시침과 분침 모두 겹쳤을 때, 중복이므로 하나를 제거해준다.
시계는 360도이므로, 360도를 넘어선다면, % 360을 통해 넘지 않도록 수정해준다.
// 1초 이후에 겹쳐진 시각을 카운팅하기
static int timePast() {
int res = 0;
double prevH = hDegree;
double prevM = mDegree;
double prevS = sDegree;
hDegree += (1.0 / 120);
mDegree += 0.1;
sDegree += 6.0;
if(Double.compare(prevH, prevS) > 0 && Double.compare(hDegree, sDegree) <= 0) res++;
if(Double.compare(prevM, prevS) > 0 && Double.compare(mDegree, sDegree) <= 0) res++;
if((Double.compare(prevH, prevM) > 0 && Double.compare(prevH, prevS) > 0)
&& (Double.compare(hDegree, mDegree) <= 0 && Double.compare(hDegree, sDegree) <= 0)) res--;
if(hDegree >= 360) hDegree %= 360;
if(mDegree >= 360) mDegree %= 360;
if(sDegree >= 360) sDegree %= 360;
return res;
}
처음 시작하는 시점과 종료하는 시점은 우리가 시점의 변화를 통해서 서로 겹치는지 판단하지 않으므로 초기 시각과 종료 시각에 대해 각각 조건문을 통해 비교해준다.
여기서 겹쳐지는 부분은 12:00:00 이거나 00:00:00이므로 시침, 초침, 분침이 동일한 경우를 제외하고는 없다.
static double hDegree, mDegree, sDegree;
public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
int count = 0;
// 초기 시각의 각도
calculateDegree(h1, m1, s1);
// 시작 시간과 종료 시간을 초로 변환
int start = h1 * 3600 + m1 * 60 + s1;
int end = h2 * 3600 + m2 * 60 + s2;
if(Double.compare(hDegree, mDegree) == 0 || Double.compare(mDegree, sDegree) == 0) count++;
// 시작 시간과 종료 시간이 동일해질 때, 종료
while(start < end) {
start++;
count += timePast();
}
calculateDegree(h2, m2, s2);
if(Double.compare(hDegree, mDegree) == 0 || Double.compare(mDegree, sDegree) == 0) count++;
return count;
}
전체 코드
import java.util.*;
import java.io.*;
class Solution {
static double hDegree, mDegree, sDegree;
public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
int count = 0;
// 초기 시각의 각도
calculateDegree(h1, m1, s1);
// 시작 시간과 종료 시간을 초로 변환
int start = h1 * 3600 + m1 * 60 + s1;
int end = h2 * 3600 + m2 * 60 + s2;
if(Double.compare(hDegree, mDegree) == 0 || Double.compare(mDegree, sDegree) == 0) count++;
// 시작 시간과 종료 시간이 동일해질 때, 종료
while(start < end) {
start++;
count += timePast();
}
calculateDegree(h2, m2, s2);
if(Double.compare(hDegree, mDegree) == 0 || Double.compare(mDegree, sDegree) == 0) count++;
return count;
}
// 1초 이후에 겹쳐진 시각을 카운팅하기
static int timePast() {
int res = 0;
double prevH = hDegree;
double prevM = mDegree;
double prevS = sDegree;
hDegree += (1.0 / 120);
mDegree += 0.1;
sDegree += 6.0;
if(Double.compare(prevH, prevS) > 0 && Double.compare(hDegree, sDegree) <= 0) res++;
if(Double.compare(prevM, prevS) > 0 && Double.compare(mDegree, sDegree) <= 0) res++;
if((Double.compare(prevH, prevM) > 0 && Double.compare(prevH, prevS) > 0)
&& (Double.compare(hDegree, mDegree) <= 0 && Double.compare(hDegree, sDegree) <= 0)) res--;
if(hDegree >= 360) hDegree %= 360;
if(mDegree >= 360) mDegree %= 360;
if(sDegree >= 360) sDegree %= 360;
return res;
}
static void calculateDegree(int h, int m, int s) {
hDegree = (h % 12) * 30.0 + m * 0.5 + s * (1.0 / 120);
mDegree = m * 6.0 + s * 0.1;
sDegree = s * 6.0;
}
}
728x90
반응형