"09:02:43" 같은 문자열에서 숫자를 꺼내고, 계산하고, 다시 같은 모양으로 출력하는 일. 코딩테스트에서 반복해서 나오는 형태다.
숫자를 꺼내는 세 방법
꺼내는 방법이 셋이다.
String time = "09:02:43";
// 1. 자릿수를 직접 계산
int hour = (time.charAt(0) - '0') * 10 + (time.charAt(1) - '0');
// 2. substring + parseInt
int hour = Integer.parseInt(time.substring(0, 2));
// 3. split
String[] t = time.split(":");
int hour = Integer.parseInt(t[0]);1번은 구분자가 없고 자릿수가 고정일 때, 2번은 위치가 고정일 때, 3번은 구분자가 있을 때다. 실무에서든 문제에서든 3번이 가장 안전하다. 자릿수가 바뀌어도 깨지지 않기 때문이다. 1번이 동작하는 이유는 `- ‘0’`이 문자를 숫자로 바꾸기 때문이다.
가장 작은 단위로 통일하기
시, 분, 초처럼 계층적인 단위를 빼고 더할 때는 두 가지 길이 있다. 작은 단위부터 내림하는 쪽은 이렇게 된다.
if (sec < 0) { sec += 60; min--; }
if (min < 0) { min += 60; hour--; }
if (hour < 0) { hour += 24; }가장 작은 단위로 통일하는 쪽은 이렇다.
int now = h1 * 3600 + m1 * 60 + s1;
int want = h2 * 3600 + m2 * 60 + s2;
int diff = want - now;
if (diff < 0) diff += 24 * 3600;
int hour = diff / 3600;
int min = (diff % 3600) / 60;
int sec = diff % 60;두 번째가 낫다. 조건 분기가 사라지고 몫과 나머지만 남는다. 10000초를 예로 보면 10000 = 3600 × 2 + 2800이고 2800 = 60 × 46 + 40이라 2시간 46분 40초다. 나눗셈의 몫이 큰 단위, 나머지가 남은 값이라는 규칙 하나로 끝난다. 계층적 단위를 만나면 일단 가장 작은 단위로 펴서 계산하고 마지막에 다시 나눈다. 날짜, 거리, 금액 어디에나 적용된다.
정수 나눗셈으로 올림하기
같은 발상의 짝이 되는 요령이 정수 나눗셈으로 올림하기다. 6과 9를 뒤집어 쓸 수 있으니 둘을 합쳐 2개당 1세트가 필요한 문제를 생각해보자. (count6 + count9) / 2로 하면 3개일 때 3 / 2 = 1이 되어 모자란다. 그렇다고 무조건 1을 더하면 4개일 때 3세트가 되어 남는다.
(count6 + count9 + 1) / 2나누기 전에 1을 더한다. 정수 나눗셈이 버림이니, 1을 미리 얹으면 딱 떨어질 때는 그대로이고 남을 때만 하나 올라간다. (a + b - 1) / b가 일반형이다.
printf 포맷 코드
출력 형식은 printf 포맷 코드로 맞춘다. %s가 문자열, %c가 문자 하나, %d가 정수, %f가 부동소수이고, %o와 %x가 8진수와 16진수, %%가 % 문자 자체다.
System.out.printf("%02d:%02d:%02d", h, m, s);%02d는 최소 2자리로 맞추고 남는 앞자리를 0으로 채운다. 시간 출력에서 9:2:43이 아니라 09:02:43이 나오게 하는 것이 이 하나다. %.3f는 소수점 아래 3자리까지다. C의 printf와 같은 규약이고, 파이썬의 `%` 포매팅도 이것을 그대로 물려받았다.