알고리즘/프로그래머스 Level2

[PCCP 기출문제] 아날로그 시계

류창 2024. 2. 19. 21:01
반응형

 

 

문제 분석

 

문제 목표 : 초침이   시침/분침이 만나는 횟수 구하기

 

할말이 많은 문제다.

 

이 문제를 어떻게 접근할것인가 큰 문제다.

 

결론부터 말하자면,  대부분의 사람들이 이 문제를 "사고력"으로 접근하였다. 

 

즉, 매 초  각도계산하면서 시침/분침과 겹치는지 완전탐색같은건 안돌린다는것이다.

 

=> 사고력으로 접근한다는것은 규칙이 있다.

 

 

하나의 예시를 줬는데 이걸 잘 이용해 먹어야한다.

 

간단하게 규칙을 계산해 보자.

 

1. 1분에 초침은 1바퀴를 돈다.

2. 1바퀴를 돌면, 일반적으로  시침과 분침을 만나게 된다. 

3. 즉, 1분이 자나가면 알람이 2번은 울린다.

 

이 규칙대로면 1시간 =  120번,  24시간 = 2880번이다.

 

잃어버린 28번은 무엇인가?

 

이걸 잘 찾아내는것이 문제의 핵심이다. 

 

우선 분침이 정각이 되기전 1분전 상황을 살펴보자. 

EX)  X시 59분 -> (X+1)시 00분

 

시뮬레이션을 돌려보면, 초침과 분침은 만나지않는다.

즉, 1시간 마다 1번의 알람이 생략된다.

 

이럼에도 불구하고 4번이 더 남는다. 

 

이것은 초침과 시침이  정각으로 모였을때의 소실이다.

 

시침이 정각으로 모일때는 딱 2번  0시 0분 0초,  12시 0분 0초  2곳이다. 

 

분침과 같은 이론으로 2번이 생략된다.

 

또한, 0시 0분 0초와 12시 0분 0초에는 특수한 경우가 발생되는데,  시/분/초가 모두 모인다. 

문제에서 다음과 같이 모두 모이는 경우 1번으로 처리하기때문에  생략을 1번더 해줘야한다. 

 

즉, 잃어버린 4번의 이유를 찾았다.

 

2880-24-4 = 2852

 

 

 

 

여기까진 좋은데, 문제는  시작시간과 도착시간이 정각이 아니다. 

 

즉, X초 동안 몇번 울렸는지를 구해야한다. 

 

위에서 아날로그의 규칙을 제대로 파악했다면 식을 짤수가있다.

 

분침이 1바퀴를 돌때를 추측해보자.  분침이 1바퀴를 도는데 1시간 =3600초가 걸린다.

 

1시간동안 분침과 초침은 60바퀴 초침간에는 59번 울린다. 즉,  3600/59초 마다 1번씩 울린다. (약, 60초안되는 시간같다)

 

시침도 마찬가지로 1바퀴를 돌때, 초침은 720바퀴 시침이 1바퀴를 도는데 12시간 = 43200초가 걸린다.

 

12시간동안 초침은 719바퀴를돈다. 즉, 43200/719초 마다 1번씩 울린다.

 

이걸 수식으로 나타내면 다음과 같다. 

 

 

 

문제 풀이 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Solution {
    public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
        int answer = 0;
        
    
        //  0초 ~ 23시 59분 59초가 2852인 이유 추측해보자
        //  1분 = 2번  60분 = 120  0초~59분 59초라 가정, 119번 울림 (60분 제외)
        //  118*24 = 2832 
        //  119*24 = 2856 4번이 생략이됨 왜일까..?
        //  0시 , 12시는 시 분 초침이 모두겹침 -2 카운트
        //  11시 59분 ->12시 , 23시 59분 -> 0시  초침이 만나는 일이 발생안함 -2 
        //  즉 , 0시 ,12시 부근에 각각 -2번 생략이된다.
        
        //But, 이 법칙은 끝나는시각이 정각일경우만 유효하다.
        
        int bonus=0;
        
        //이것은 시작시간이 알람일경우 시작하자마자 알람이 울리기때문에
        // +1번을 해줘야한다.
        if(h1*3600+m1*60+s1==0 ||h1*3600+m1*60+s1==43200){
            bonus=1;
        }
        
        return getCount(h2,m2,s2)-getCount(h1,m1,s1)+bonus;
    }
    
    //끝나는 시각은 정각이 아니다.  유동적이다. 
    //즉,  x초동안 몇번 울리는지를 정확하게 알아야함
    // 초-분 관점  60분 = 3600초 , 초침은 60바퀴 1바퀴 =1번울림
    // 3600초동안 59번알람 (마지막바퀴는 안만남)
    // 즉 , 3600/59초당 1번 울림
    //그렇다면, x초/59를 하면 x초동안 시-분 알람을 구할수있지않나?
    // 초-시 관점  시침이 0시~12시 까지 12시*3600=43200
    // 43200초동안, 초침은 720바퀴 
    // 즉 , 43200초동안 719번 알람 (마지막 바퀴는 안만남)
    //   463200/719초당 1번 울림
    
    public int getCount(int h1,int m1, int s1){
        
         int total = h1*3600+m1*60+s1;
        
         int m_alram = total*59/3600;
        
         int h_alram = total * 719/43200;
 
         int answer = m_alram+h_alram;
 
         if(h1>=12){
             answer--;
         }
        return answer;
    }
}
cs

 

반응형