본문 바로가기

[IT] 코딩테스트/[문제 및 풀이] 프로그래머스

[프로그래머스] PCCP 기출문제 3번 (아날로그 시계) / 자바(Java)

728x90

문제

https://school.programmers.co.kr/learn/courses/30/lessons/250135?language=java

 

프로그래머스

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

programmers.co.kr

 


해설

시침, 분침과 초침이 만나는 횟수를 구하는 문제입니다.

 

특정 범위의 시간을 구하기 까다로워 단순하게 만들기 위해 00시 00분 00초에서 시작 시간과 끝 시간의 횟수를 구해 그 차이를 구하는 것으로 변형하여 해결하였습니다.

 

각 시간을 구하는데에는

1. 시침이 해당 시점까지 몇번 초침과 만났는가

2. 분침이 해당 시점까지 몇번 초침과 만났는가

3. 해당 시점에 초침이 시침을 지났는가

4. 해당 시점에 초침이 분침을 지났는가

5. 시침, 분침, 초침이 모두 만난 순간이 몇번인가

 

총 5가지 가능성을 고려해야 합니다.

 

1. 해당 시점까지 시침과 초침이 만난 경우

시침은 1시간에 30도씩 이동하기 때문에 시간당 60번, 분당 1번씩 만납니다

단 12시가 될때 00분 00초가되어 시간 계산이 겹치므로 12시 이후의 시간인 경우 1회 감소합니다.

 

2. 해당 시점까지 분침과 초침이 만난 경우

시침과 비슷하지만 분침은 시침의 12시와 같은 겹침이 1시간에 1번씩 발생해 시간당 59번, 분당 1번씩 만납니다.

 

3. 해당 시점에 시침과 초침이 만난 경우

시침의 위치는 시, 분, 초 침에 의해 결정되므로 시침의 각도가 초침의 각도보다 작거나 같은경우 만난것으로 1회 추가합니다.

 

초침의 각도는 초침이 360도를 60초만에 회전하므로 : 360/60 * s가 됩니다.

시침의 각도는 

시 기준으로 12시 이후는 0시와 동일하고 360도를 12시간만에 회전하므로 360/12 * (h%12)

분 기준으로 360/(12*60) * m

초 기준으로 360/(12*60*60) *s

의 합이 됩니다.

 

4. 해당 시점에 초침이 분침을 지났는가

분침의 위치는 분, 초침에 의해 결정되어 분침의 각도가 초침의 각도보다 작거나 같은 경우 1회 추가합니다.

 

초침의 각도는 위와 동일하며

분침의 각도는

분 기준으로 360도를 60분에 회전하므로 360/60 * m

초 기준으로 360/60/60 * s 의 합이 됩니다.

 

 

5. 시침, 분침, 초침이 모두 만난 순간이 몇번인가

시,분,초침이 모두 만나는 순간은 00시00분00초, 12시00분00초 단 2순간입니다.

특정 시점의 횟수를 구하는데에 00시00분00초는 항상 포함되기 때문에 12시 이상인 경우에만 중복된 경우 1회를 제외합니다.

 

조건들을 찾는데 어려움이 있어 고민이 많아지는 문제였습니다.

주의점

  • 시침, 분침,  초침이 모두 만나는 시점을 주의한다
  • 분침, 시침의 각도를 구할 때 초에 따라 생긴 변화 또한 포함한다.
  • 횟수의 차이를 통해 해결하는데 시간의 범위가 앞, 뒤가 포함되어야 함으로 정각에 시작한 경우 1을 추가해야한다.

코드

class Solution {
    public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
        // 0시0분0초에서 입력값까지의 알람값을 각각 구해서 빼준다.
        int answer = getAlarms(h2,m2,s2)-getAlarms(h1,m1,s1);
        // 정각에 시작한 경우포함시켜 준다.
        if(s1==0 && m1==0) answer++;
        return answer;
    }
    
    int getAlarms(int h, int m, int s){
        int alarms = 0;
        
        // 일반적인 경우(특정시, 특정분의 00초에서 59초가 모두 포함된 경우) 1분에 한번씩, 1시간에 60번 만난다.
        // 단 분침은 60분은 00분과 같은 위치임으로 제외하여 총 59번 만난다.
        int mCount = h * (60-1) + m;
        
        // 시침도 12시와 00시가 같은 위치이고 시간의 범위는 23시59분59초까지이므로 12시이상 인 경우 1회는 제외한다.    
        int hCount = h * 60 + m;
        if(h>=12) hCount--;
        
        
        // 초침의 각도 = s * 360/60
        // 분침의 각도 = m * 360/60 + s * 360/(60*60)
        if(m*6+s*0.1 <= s*6) mCount++;
        
        // 시침의 각도 = (h%12) * 360/12 + m * 360/(12*60) + s * 360 / (12*60*60)
        if(30*(h%12)+0.5*m + s * (1 / 120) <= s*6) hCount++;
        

        alarms = mCount + hCount;
        // 12시 00분 00초를 지난 경우 시,분,초가 모두 중복되어 alarm의 수를 줄인다.
        if(h>=12) alarms--;
        return alarms;
    }
}
728x90