프로그래머스/자바 Lv2

[프로그래머스] Java Lv2. 코딩테스트 연습 > PCCP 기출문제 > 아날로그 시계 250135

행수쌤 2024. 11. 1. 11:21
728x90
반응형

문제설명

초침이 시침/분침과 겹칠 때마다 알람이 울리는 기능이 있는 시계가 있습니다. 특정 기간 동안 알람이 울린 횟수를 알고 싶습니다.

접근방법

  1. 아날로그 시계 360도를 기준으로 1초마다 시침, 분침, 초침의 위치를 판단
  2. (현재의 시침 위치 - 현재의 초침 위치) 의 부호와 (1초후의 시침 위치 - 1초후의 초침 위치) 의 부호가 다르거나 차이가 0이면 초침이 시침을 지나감

핵심로직

  1. 시작 시간과 끝 시간을 초 단위로 변경 후 for문을 돌려 1초마다 시침, 분침, 초침의 위치관계 파악
    • 시침 : 초당 360 / 60(초) * 60(분) * 12(시) = 1 / 120
    • 분침 : 초당 360 / 60(초) * 60(분) = 1 / 10
    • 초침 : 초당 360 / 60 = 6
  2. 현재의 (시/분침 위치 - 초침 위치) * 1초후의 (시/분침 위치 - 초침 위치) <= 0 이면 초침이 시/분침을 지나갔거나 일치하는 상태이므로 answer ++
  3. 마지막 회차에 정확하게 일치하는 경우 판단
  4. 시/분/초침이 동시에 일치하게 되는 경우 판단
  5. double 사용 시 계산 오류가 발생하여 오답 케이스 발생. BigDecimal 사용하여 해결

입출력 예

  • h1 = 0
  • m1 = 5
  • s1 = 30
  • h2 = 0
  • m2  = 7
  • s2 = 0
  • result = 2

코드 작성

import java.math.*;

class Solution {
    public int solution(int h1, int m1, int s1, int h2, int m2, int s2) {
        // 시작 시간과 종료 시간을 초 단위로 변환
        int startTime = h1 * 3600 + m1 * 60 + s1;
        int endTime = h2 * 3600 + m2 * 60 + s2;
        int different = endTime - startTime; // 전체 시간 차이 (초 단위)
        
        int answer = 0; // 결과 값을 저장할 변수
        BigDecimal deivde120 = new BigDecimal("120"); // 시침의 이동 속도에 사용
        BigDecimal deivde10 = new BigDecimal("10"); // 분침의 이동 속도에 사용
        BigDecimal deivdeDot1 = new BigDecimal("0.1"); // 분침의 세분화
        BigDecimal deivde6 = new BigDecimal("6"); // 초침의 이동 속도에 사용
        BigDecimal remainder360 = new BigDecimal("360"); // 360도를 기준으로 한 바퀴

        // 각 초에 대해 초침, 분침, 시침의 위치를 계산하여 특정 조건을 확인
        for (int i = 0; i < different; i++) {
            int currentTime = startTime + i; // 현재 초 단위 시간
            BigDecimal hNeedle = new BigDecimal(String.valueOf(currentTime));
            BigDecimal mNeedle = new BigDecimal(String.valueOf(currentTime));
            BigDecimal sNeedle = new BigDecimal(String.valueOf(currentTime));
            
            // 시침 위치 계산
            hNeedle = hNeedle.divide(deivde120, 4, RoundingMode.HALF_UP).remainder(remainder360);
            // 분침 위치 계산
            mNeedle = mNeedle.divide(deivde10, 1, RoundingMode.HALF_UP).remainder(remainder360);
            // 초침 위치 계산
            sNeedle = sNeedle.multiply(deivde6).remainder(remainder360);

            int nextTime = currentTime + 1;
            // 다음 초의 시침 위치
            BigDecimal hNeedle2 = new BigDecimal(String.valueOf(nextTime))
                .divide(deivde120, 4, RoundingMode.HALF_UP).remainder(remainder360);
            // 다음 초의 분침 위치
            BigDecimal mNeedle2 = mNeedle.add(deivdeDot1);
            // 다음 초의 시침 위치
            BigDecimal sNeedle2 = sNeedle.add(deivde6);

            // 시침이 기준값을 넘지 않도록 처리
            if (hNeedle.compareTo(deivde120) == 1 && hNeedle2.compareTo(deivde120) <= 0) {
                hNeedle2 = hNeedle2.add(remainder360);
            }

            // 초침이 분침을 지나가는지 여부를 확인
            if (sNeedle2.compareTo(mNeedle2) != 0 
                && sNeedle.compareTo(mNeedle) * sNeedle2.compareTo(mNeedle2) <= 0) {
                answer++;
            } else if (nextTime == endTime && sNeedle2.compareTo(mNeedle2) == 0) {
                answer++;
            }

            // 초침이 시침을 지나가는지 여부를 확인
            if (sNeedle2.compareTo(hNeedle2) != 0 
                && sNeedle.compareTo(hNeedle) * sNeedle2.compareTo(hNeedle2) <= 0) {
                answer++;
            } else if (nextTime == endTime && sNeedle2.compareTo(hNeedle2) == 0) {
                answer++;
            }

            // 초침, 분침, 시침이 일치할 때의 예외 처리
            if (sNeedle.compareTo(hNeedle) == 0 && hNeedle.compareTo(mNeedle) == 0) {
                answer -= 1;
            } else if (nextTime == endTime 
                       && sNeedle2.compareTo(hNeedle2) == 0
                       && hNeedle2.compareTo(mNeedle2) == 0) {
                answer -= 1;
            }
        }
        return answer;
    }
}

 

728x90
반응형