알고리즘

[프로그래머스] PCCP 기출문제 아날로그 시계 - Java & JavaScript

BGK97 2025. 1. 25. 23:06

문제 출처

https://school.programmers.co.kr/learn/courses/30/lessons/250135

문제 설명

시침, 분침, 초침이 있는 아날로그시계가 있습니다. 시계의 시침은 12시간마다, 분침은 60분마다, 초침은 60초마다 시계를 한 바퀴 돕니다. 따라서 시침, 분침, 초침이 움직이는 속도는 일정하며 각각 다릅니다. 이 시계에는 초침이 시침/분침과 겹칠 때마다 알람이 울리는 기능이 있습니다. 당신은 특정 시간 동안 알람이 울린 횟수를 알고 싶습니다.

다음은 0시 5분 30초부터 0시 7분 0초까지 알람이 울린 횟수를 세는 예시입니다.

  • 가장 짧은 바늘이 시침, 중간 길이인 바늘이 분침, 가장 긴 바늘이 초침입니다.
  • 알람이 울리는 횟수를 세기 시작한 시각은 0시 5분 30초입니다.
  • 이후 0시 6분 0초까지 초침과 시침/분침이 겹치는 일은 없습니다.
  • 약 0시 6분 0.501초에 초침과 시침이 겹칩니다. 이때 알람이 한 번 울립니다.
  • 이후 0시 6분 6초까지 초침과 시침/분침이 겹치는 일은 없습니다.
  • 약 0시 6분 6.102초에 초침과 분침이 겹칩니다. 이때 알람이 한 번 울립니다.
  • 이후 0시 7분 0초까지 초침과 시침/분침이 겹치는 일은 없습니다.

0시 5분 30초부터 0시 7분 0초까지는 알람이 두 번 울립니다. 이후 약 0시 7분 0.584초에 초침과 시침이 겹쳐서 울리는 세 번째 알람은 횟수에 포함되지 않습니다.

다음은 12시 0분 0초부터 12시 0분 30초까지 알람이 울린 횟수를 세는 예시입니다.

 

  • 알람이 울리는 횟수를 세기 시작한 시각은 12시 0분 0초입니다.
  • 초침과 시침, 분침이 겹칩니다. 이때 알람이 한 번 울립니다. 이와 같이 0시 정각, 12시 정각에 초침과 시침, 분침이 모두 겹칠 때는 알람이 한 번만 울립니다.
  • 이후 12시 0분 30초까지 초침과 시침/분침이 겹치는 일은 없습니다.

12시 0분 0초부터 12시 0분 30초까지는 알람이 한 번 울립니다.

알람이 울리는 횟수를 센 시간을 나타내는 정수 h1, m1, s1, h2, m2, s2가 매개변수로 주어집니다. 이때, 알람이 울리는 횟수를 return 하도록 solution 함수를 완성해주세요.


제한사항
  • 0 ≤ h1, h2 ≤ 23
  • 0 ≤ m1, m2 ≤ 59
  • 0 ≤ s1, s2 ≤ 59
  • h1시 m1분 s1초부터 h2시 m2분 s2초까지 알람이 울리는 횟수를 센다는 의미입니다.
    • h1시 m1분 s1초 < h2시 m2분 s2초
    • 시간이 23시 59분 59초를 초과해서 0시 0분 0초로 돌아가는 경우는 주어지지 않습니다.

입출력 예 설명

입출력 예 #1

문제 예시와 같습니다.

입출력 예 #2

문제 예시와 같습니다.

입출력 예 #3

0시 6분 1초부터 0시 6분 6초까지 초침과 시침/분침이 겹치는 일은 없습니다. 따라서 알람이 울리지 않으며 0을 return 해야 합니다.

입출력 예 #4

  • 11시 59분 30초부터 11시 59분 59초까지 초침과 시침/분침이 겹치는 일은 없습니다.

  • 12시 0분 0초에 초침과 시침, 분침이 겹칩니다. 이때 알람이 한 번 울립니다.

11시 59분 30초부터 12시 0분 0초까지 초침과 시침/분침이 겹치는 횟수는 1이며 따라서 알람이 한 번 울립니다.

입출력 예 #5

  • 약 11시 58분 59.917초에 초침과 시침이 겹칩니다. 이때 알람이 한 번 울립니다.

11시 58분 59초부터 11시 59분 0초까지 초침과 시침/분침이 겹치는 횟수는 1이며 따라서 알람이 한 번 울립니다.

입출력 예 #6

  • 약 1시 5분 5.085초에 초침과 분침이 겹칩니다. 이때 알람이 한 번 울립니다.
  • 약 1시 5분 5.424초에 초침과 시침이 겹칩니다. 이때 알람이 한 번 울립니다.

1시 5분 5초부터 1시 5분 6초까지 초침과 시침/분침이 겹치는 횟수는 2며 따라서 알람이 두 번 울립니다.

입출력 예 #7

0시 0분 0초부터 23시 59분 59초까지 초침과 시침/분침이 겹치는 횟수는 2852며 따라서 알람이 총 2852번 울립니다.

풀이 방법

  • 아날로그의 시계 이므로, 초당 각도가 변화되는 것을 인지하고 풀어야한다.
  • 따라서 현재의 시간과 1초뒤의 상황을 각도로 변환해준 다음 끝까지 반복하여 값이 넘어가는 경우 ans에 카운트를 해준다

예외 상황

  • 초기 시간이 0시이거나, 12시이거나 하면 먼저 값을 증가시키고 시작행야한다.
  • 또한, 반복 도중 정각이 되는 경우(시,분,초침 모두 한위치)에는 1을 감소시켜주어야한다.(이전 if문에서 두번 증가되었음)

풀이코드 - Java

class Solution {
    public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
        int answer = 0;
        //시간을 초로 변환하기
        double start = h1 * 3600 + m1 * 60 + s1;
        double end = h2 * 3600 + m2 * 60 + s2;
        
        //0시이거나, 12시이거나
        if(start == 0 || start == 12 * 3600){
            answer++;
        }
        
        while(start < end){
            //각도로 시간 계산하기
            double hAngle = start / 120 % 360 ;
            double mAngle = start / 10 % 360;
            double sAngle = start * 6 % 360;
            
            //다음 각도 보기
            double nextHAngle = checkOnTime((start + 1) / 120 % 360);
            double nextMAngle = checkOnTime((start + 1) / 10 % 360);
            double nextSAngle = checkOnTime((start + 1) * 6 % 360);
            
            //시침과 초침이 마주치거나, 분침과 초침이 마주치거나.
            if(sAngle < hAngle && nextHAngle <= nextSAngle){
                answer++;
            }
            if(sAngle < mAngle && nextMAngle <= nextSAngle){
                answer++;
            }
            //동시에 겹치는 경우 1번 빼주기
            if(nextSAngle == nextMAngle && nextSAngle == nextHAngle){
                answer--;
            }
            
            start++;
        }
        return answer;
    }
    
    public double checkOnTime(double x){
        if(x == 0){
            return 360;
        }
        else return x;
    }
}

Java 코드 결과

풀이 코드 - JavaScript 

  • 감을 잃지않기위해, 자바스크립트로도 풀어보았다.
function solution(h1, m1, s1, h2, m2, s2) {
    var answer = 0;
    //시간 초로 변환
    let start = h1 * 3600 + m1 * 60 + s1;
    let end = h2 * 3600 + m2 * 60 + s2;
    
    if(start === 0 || start === 12 * 3600){
        answer++;
    }
    
    while(start < end){
        const hAngle = start / 120 % 360;
        const mAngle = start / 10 % 360;
        const sAngle = start * 6 % 360;
        
        const nextHAngle = checkOnTime((start + 1) / 120 % 360);
        const nextMAngle = checkOnTime((start + 1) / 10 % 360);
        const nextSAngle = checkOnTime((start + 1) * 6 % 360);
        
        if(sAngle < hAngle && nextHAngle <= nextSAngle){
            answer++;
        }
        if(sAngle < mAngle && nextMAngle <= nextSAngle){
            answer++;
        }
        if(nextSAngle === nextMAngle && nextSAngle === nextHAngle){
            answer--;
        }
        
        start++;
        
    }
    return answer;
}
    
function checkOnTime(x){
    if(x === 0){
        return 360;
    }
    else return x;
}
  • 사실 각도가 중요한 문제라... 코드에 별 차이는 없다.

JavaScript 결과

회고

  • 왜 자바스크립트가 더 빠르지