개발자는 기록이 답이다

[백준/BOJ][Java][13223] 소금 폭탄 본문

알고리즘/백준

[백준/BOJ][Java][13223] 소금 폭탄

slow-walker 2023. 8. 24. 11:02

2023.08.21 - [Java] - Java, String의 constant pool과 Heap의 차이

 

Java, String의 constant pool과 Heap의 차이

Java String 문자열? 순서를 가진 문자들의 집합 “쌍따옴표를 통해 나타낼 수 있음” 글자, 단어, 문장, 문서 등 문자로 구성된 자료형 // 기본 자료형 int var_integer = 10; double var_real - 3.141592; char var_ch

strong-park.tistory.com


https://www.acmicpc.net/problem/13223

 

13223번: 소금 폭탄

첫째 줄에는 현재 시각이 hh:mm:ss로 주어진다. 시간의 경우 0≤h≤23 이며, 분과 초는 각각 0≤m≤59, 0≤s≤59 이다. 두 번째 줄에는 소금 투하의 시간이 hh:mm:ss로 주어진다.

www.acmicpc.net

 

내가 푼 풀이

문자열로 받아서 숫자로 하는건 하겠는데, 숫자 계산을 잘 못하겠더라구요.

수학적인 머리가 부족한게 이렇게 사람을 답답하게 만드는게 속상합니다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String now = sc.next();
        String targetTime = sc.next();

        String[] currentSplit = now.split(":");
        int currentHour = Integer.parseInt(currentSplit[0]);
        int currentMinute = Integer.parseInt(currentSplit[1]);
        int currentSecond =  Integer.parseInt(currentSplit[2]);

        String[] targetSplit = targetTime.split(":");
        int targetHour = Integer.parseInt(targetSplit[0]);
        int targetMinute = Integer.parseInt(targetSplit[1]);
        int targetSecond =  Integer.parseInt(targetSplit[2]);


        int gasHour = targetHour - currentHour;
        int gasMunute = targetMinute - currentMinute;
        int gasSecond = targetSecond - currentSecond;

        if (gasSecond < 0) {
            gasSecond += 60;
            gasMunute--;
        }
        if (gasMunute < 0) {
            gasMunute += 60;
            gasHour--;
        }
        if (gasHour <= 0) {
            gasHour += 24;
        }

       System.out.printf("%02d:%02d:%02d", gasHour, gasMunute, gasSecond);
    }
}

 

메모리 시간 언어 코드 길이
17532KB 204ms Java11 1172B

 

강의 풀이

- 이 시간은 1초보다 크거나 같고, 24시간보다 작거나 같다.

- 입력 값 2개가 완전히 똑같은 시간이 들어왔을때, 00:00:00 이 나오게 하면 안된다는 의미 -> 24:00:00으로 나오게 해야 합니다.

if (needSecoundAmount <= 0)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String now = sc.next();
        String targetTime = sc.next();

        String[] currentSplit = now.split(":");
        int currentHour = Integer.parseInt(currentSplit[0]);
        int currentMinute = Integer.parseInt(currentSplit[1]);
        int currentSecond =  Integer.parseInt(currentSplit[2]);
        int currentAmount = currentHour * 3600 + currentMinute * 60 + currentSecond;

        String[] targetSplit = targetTime.split(":");
        int targetHour = Integer.parseInt(targetSplit[0]);
        int targetMinute = Integer.parseInt(targetSplit[1]);
        int targetSecond =  Integer.parseInt(targetSplit[2]);
        int targetAmount = targetHour * 3600 + targetMinute * 60 + targetSecond;

        int needSecoundAmount = targetAmount - currentAmount;
        if (needSecoundAmount <= 0)
            needSecoundAmount += 24 * 3600;
        int needHour = needSecoundAmount / 3600;
        int needMinute = (needSecoundAmount % 3600) / 60;
        int needSecond = needSecoundAmount % 60;
        System.out.printf("%02d:%02d:%02d", needHour, needMinute, needSecond);
    }
}
메모리 시간 언어 코드 길이
17624KB 204ms Java11 1234B

강의 문제 풀이

 

문제 : HH:MM:SS 포맷의 두 시각의 차이를 HH:MM:SS 포맷으로 출력하기

 

1. ':' 문자를 기준으로 시간, 분, 초를 쪼갠다.

- 어떻게 쪼개지..? 반복문을 도나..?

- 각 단위의 인덱스에서 10의 자리와 1의 자리를 구해 계산할 수 있다

       // 방법 1
       
       String time = "09:10:59";
        // 자리수 값이라고 했으니까, 문자로된 숫자에 아스키 0값을 빼줘야한다
        // 숫자 캐릭터타입에 아스키코드인 '0'을 빼면 숫자 그대로 int타입으로 바꿔준다
        int hour = (time.charAt(0) - '0') * 10 + time.charAt(1) - '0';
        int minute = (time.charAt(3) - '0') * 10 + time.charAt(4) - '0';
        int second = (time.charAt(6) - '0') * 10 + time.charAt(7) - '0';

- String.substring을 사용하면 원하는 문자열만 떼올 수 있다.

        // 방법 2
        
        String time = "09:10:59";
        // parseInt에 숫자로만 이루어진 문자열을 전달해주면 해당 문자열이 표현한 숫자를 정수로 반환해준다
        int hour = Integer.parseInt(time.substring(0,2));
        int minute = Integer.parseInt(time.substring(3,6));
        int second = Integer.parseInt(time.substring(6,8));

- String.split을 사용하면 토큰을 기준으로 문자열을 나눠준다.

        // 방법 3

        // split함수는 어떤 문자열을 인자로 받아서 해당 문자열 기준으로 time을 나눠준다
        String[] time = "09:10:59".split(":");
        int hour = Integer.parseInt(time[0]);
        int minute = Integer.parseInt(time[1]);
        int second = Integer.parseInt(time[2]);

2. 두 시간, 분, 초의 차이를 계산한다.

- 차이는 투하 시각에서 현재 시각을 빼서 구할 수 있다.

- 하지만 현재 시간에서 날이 바뀌면 투하 시각이 현재 시각보다 앞설 수 있다. 시간이 음수가 나오면..?

        // 현재 시각으로 투하 시각까지 필요한 시간
        int needHour = dropHour - currentHour;
        int needMinute = dropMinute - currentMinute;
        int needSecond = dropSecond = currentSecond;
        // 매 값을 확인하고 조정하는 방법
        // 각 단위가 음수가 나오면 더 큰 단위에서 내림하여 가져온다.
        if (needSecond < 0) { // 1분을 60초로 변환해 더해준다.
            needSecond += 60; needMinute--;}
        if (needMinute < 0) { // 1시간을 60분으로 변환해 더해준다.
            needMinute += 60; needHour--;}
        if (needHour < 0) // 하루를 24시간으로 변환해 더해준다.
            needHour += 24;

- 하지만 이렇게 매번 값을 확인하고 조정하는 방법 말고 가장 작은 단위로 통일해서 계산하는 방법도 있다.

        // 이런 방법은 데이터 단위인, B, KB, MB, GB에서도 유용하다
        // 모든 단위를 가장 작은 단위인 바이트로 맞춰서 계산하면 편하다
        // 마찬가지로 시간을 할때는 가장 작은 단위인 초를 기준으로 1시간이 3600초, 1분이 60초
        int currentSecondAmount = currentHour * 3600 + currentMinute * 60 + currentSecond;
        int dropSecondAmount = dropHour * 3600 + dropMinute * 60 + dropSecond;

        int needSecondAmount = dropSecondAmount - currentSecondAmount;
        if (needSecondAmount < 0)
            needSecondAmount += 24 * 3600;

        int needHour = needSecondAmount / 3600;
        int needMinute = (needSecondAmount % 3600) / 60;  --> 아래 글 참고
        int needSecond = needSecondAmount % 60;

 

만약에 10000초가 있다고 가정했을때 어떻게 구할 수 있을까?

10000초 =. 3600 * (2시간) + 2800초. --> 여기서 2시간은 어떻게 나오나? 10000초를 3600으로 나눈 몫
               = 2시간 + 60 * (46분) + 40초 --> 시간으로 변한건 제외하고, 나머지 2800초를 60으로 나누면 46이 몫이 된다
               = 2시간 46분 40초 --> 나머지 40은 초로 사용하면 된다


이 방법이 헷갈릴 수도 있지만, 이런 계층적 변환법에서는 아주 유용한 방법이다

3. 구해진 시간을 HH:MM:SS 형태로 출력한다.

- 만약 각 값이 한 자릿 수라면 앞에 0을 붙여 출력해야 한다.

        // 방법 1
        
        String ans = "";
        if (needHour < 10) ans += "0" + needHour + ":";
        else ans += needHour + ":";
        if (needMinute < 10) ans += "0" + needMinute + ":";
        else ans += needMinute + ":";
        if (needSecond < 10) ans += "0" + needSecond + ":";
        else ans += needSecond + ":";
        // 방법 2 (문자열 포맷 코드 사용)
        
        String ans = String.format("%02d:%02d:%02d", h, m, s);
        System.out.println(ans);
        System.out.printf("%02d:%02d:%02d", h, m, s);
코드 설명
%s 문자열(String)
%c 문자 1개(character)
%d 정수(Integer)
%f 부동소수(floeating-point)
%o 8진수
%x 16wlstn
%% Literal %(문자 % 자체)