알고리즘

[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
반응형