개발 쥬스

[프로그래머스/Java] 아날로그 시계 (pccp 기출문제) 본문

알고리즘

[프로그래머스/Java] 아날로그 시계 (pccp 기출문제)

DevJuice 2024. 7. 29. 21:47
반응형

 

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

이 문제는 단순한 알고리즘 구현 문제이지만 구현 생각 과정이 무척 까다로운 문제였습니다.

시침과 초침이 겹치는 경우, 분침과 초침이 겹치는 경우, 시침과 분침과 초침 모두 겹치는 경우 이 세가지를 나룰 때 어떤 기준을 세우면서 나눠야 하는지 과정을 한참 고민하다가 결국은 힌트를 참고하여 문제를 해결하게 되었습니다.

 

고찰 과정

우선 아날로그 상에서 시침, 분침, 초침이 모두 겹치는 경우는 정각인 경우를 제외하면 나머지 시간대에서 초침이 한 바퀴의 시간을 돌 때 각각 분침, 시침 두 번 겹치면서 돌아가게 됩니다. 그리고 문제에서 h1시 m1분 s1초에서 h2시 m2분 s2초까지 흘러갈 때 몇 번 겹치는지 구하라는 얘기가 있는데 h1시 m1분 s1초 < h2시 m2분 s2초 의 상황이 보장이 되어 있고, 23시 59분 59초에서 0시 0분 0초로 넘어가는 경우도 없다고 하였으므로 결론적으로 0시 0분 0초를 기준으로 하여 0시 0분 0초에서 h2시 m2분 s2초까지 겹치는 횟수에서 0시 0분 0초에서 h1시 m1분 s1초까지 겹치는 횟수를 빼는 방식으로 문제를 해결하였습니다.

 

과정을 세우기에 앞서 다음과 같은 상황을 염두해두어야 합니다.

  1. 59분에서 0분으로 돌아가는 상황초침과 분침이 겹치지 않는다.
  2. 11시 59분 59초에서 12시 0분 0초로 돌아가는 상황에서는 아무것도 겹치는 것이 없다.
  3. 그 이외에는 초침이 한 바퀴 돌아갈 때 모두 두 번 겹친다.

그리고 h시 m분 s초에서 시침(h), 분침(m), 초침(s)의 각도는 다음과 같습니다. 단위는 degree 입니다.

  • h = 30 * h (1시간당 30도로 움직임) + 0.5 * m(60분당 30도로 움직이므로 1분당 0.5도로 움직임) + s / 120.0(3600초당 30도로 움직임)
  • m = 6 * m(1분당 6도) + 0.1 * s(60초당 6도로 움직임)
  • s = 6* s (1초당 6도 움직임)

위 공식을 활용하여 먼저 초침과 분침 그리고 초침과 시침 각각의 각도 크기를 비교하여 초침의 각도가 큰 경우에 대해서 카운트를 해주었고, 0시 0분 부터 h시 m분까지 초침이 돌아간 횟수에서 2를 곱해주었습니다. 그리고 다음과 같은 상황에서 카운팅은 제외하였습니다.

  • 기준으로 했었던 0시 0분 0초의 카운팅은 제외
  • 59분에서 00분으로 돌아가는 상황은 h번만큼 나오므로 h만큼의 카운팅 제외
  • 12시에서 13시로 넘어가는 경우의 카운팅은 아예 없다.

이를 바탕으로 코드를 구현하였습니다.

 


코드

class Solution {
    public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
        int answer = getCount(h2, m2, s2) - getCount(h1, m1, s1);

        if ((h1 == 0 || h1 == 12) && (m1 == 0 && s1 == 0)) {
            ++answer;
        }
        
        return answer;
    }
    
    private int getCount(int h, int m, int s) {
        int count = -1; // 시작 시간 0시 0분 0초의 카운팅을 제외하였다.
        double hourDegree = (h * 30.0 + m * (1 / 2.0) + (s / 120.0)) % 360;
        double minuteDegree = (m * 6 + s * (1 / 10.0)) % 360;
        double secondDegree = (s * 6.0) % 360;
        
        // 현재 위치의 초침과 분침 시침과의 각도 비교
        if (secondDegree >= minuteDegree) {
            ++count;
        }
        
        if (secondDegree >= hourDegree) {
            ++count;
        }
        
        // 시, 분이 가리키는 위치에 따라 초침이 돌아가는 횟수가 있을 것이므로 그만큼 카운팅 (60분당 두 번 겹침)
        count += (h * 60 + m) * 2;
        count -= h; // 59분에서 00분으로 넘어가는 경우 초침, 분침이 안겹침

	// 11시 59분에서 12시 사이에는 경우 초침이 시침, 분침과 모두 안겹침
        // 12시 정각에는 초침, 시침, 분침 딱 한번만 겹침
        if (h >= 12) { 
            count -= 2; 
            // -2를 해준 이유는 처음에 각도 비교할 때 같은 경우를 두 번 카운팅 해준 것에서 하나 빼준 것과
            // 11시 59분에서 12시 사이에서 안겹치는 경우를 빼준 것이다.
        }
        
        return count;
    }
}

 

반응형