
내가 생각했을때 문제에서 원하는부분
총 T개의 테스트 케이스가 입력으로 주어지며, 첫째 줄에 T가 주어진다. (1 ≤ T ≤ 1000)
테스트 케이스의 첫째 줄에 정수 A와 B가 공백으로 구분되어 주어진다. (1 ≤ A,B ≤ 10^6)
각 테스트 케이스마다 한 줄에 잘못된 곱셈 결과가 일반 곱셈 결과와 같다면 1을, 같지 않다면 0을 출력한다.
내가 이 문제를 보고 생각해본 부분
초기 설정:
BufferedReader br: 사용자로부터 입력을 효율적으로 받기 위한 도구이다.
StringBuilder sb: 여러 테스트 케이스의 결과를 한꺼번에 모아 출력하기 위해 사용된다.
문자열을 반복해서 추가할 때 + 연산보다 훨씬 효율적이다.
int T: 첫 줄에서 읽어 들인 테스트 케이스의 총 개수이다.
테스트 케이스 반복:
for(int t = 0; t < T; t++) 루프를 통해 각 테스트 케이스를 개별적으로 처리한다.
입력 처리: 각 테스트 케이스마다 한 줄을 읽어 StringTokenizer로 A와 B 두 숫자를 분리한다.
이 숫자들은 Long.parseLong()을 통해 long 타입으로 변환된다.
A와 B가 최대 10^6까지 주어질 수 있으므로, 두 수를 곱한 결과는 int의 범위를 넘어설 수 있어 long 타입이 필요하다.
일반 곱셈 계산: normalMultiplication = A * B;를 통해 우리가 일반적으로 알고 있는 곱셈 결과를 계산한다.
'잘못된 곱셈' 계산: calculateWrongMultiplication(A, B) 메서드를 호출하여 문제에서 정의한 특별한 규칙의 "잘못된 곱셈" 결과를 계산한다.
결과 비교 및 추가: normalMultiplication == wrongMultiplication ? 1 : 0 연산을 통해 일반 곱셈과 '잘못된 곱셈' 결과가 같으면 1을, 다르면 0을 sb에 추가하고 어줄 바꿈 문자도 함께 넣준다.
최종 출력: 모든 테스트 케이스가 끝나면 System.out.println(sb);를 통해 StringBuilder에 모아둔 모든 결과를 한 번에 출력한다.
마지막으로 br.close();로 BufferedReader 자원을 해제한다.
calculateWrongMultiplication 메서드 설명:
이 메서드는 문제에서 설명하는 복잡한 "잘못된 곱셈" 규칙을 직접 구현한 부분이다.
문자열 변환: 입력받은 long A와 long B를 String.valueOf()를 사용하여 문자열 sA와 sB로 변환한다.
자릿수별로 연산하기 위함이다.
길이 정렬: if(sA.length() < sB.length()) 조건문을 사용하여 항상 s1이 s2보다 길거나 같은 길이의 문자열을 가리키도록 조정한다.
이렇게 하면 나중에 s1에 남은 자릿수를 처리하기가 편리해진다.
결과 빌더(resBuilder): StringBuilder resBuilder = new StringBuilder();를 선언하여 '잘못된 곱셈'의 중간 결과들을 문자열 형태로 저장하고 구축해 나간다.
insert(0, ...) 메서드를 사용하면 문자열의 가장 앞부분에 새로운 내용을 추가할 수 있는데, 이는 자릿수를 오른쪽(일의 자리)부터 처리할 때 매우 유용하다.
짧은 문자열 길이만큼 자릿수 곱셈:
while(i <= s2.length()) 루프는 짧은 문자열 s2의 자릿수 개수만큼 반복된다.
s1.charAt(s1.length() - i) - '0'는 s1의 오른쪽 끝에서부터 i번째 자릿수를 추출하는 방법이다. (charAt()은 0부터 시작하는 인덱스를 사용하기 때문에 s1.length() - i로 접근한다.)
-'0'을 해주면 문자(char)를 실제 숫자(int)로 변환할 수 있다.
digit1과 digit2를 이렇게 추출한다.
resBuilder.insert(0, String.valueOf(digit1 * digit2));: 추출된 두 자릿수를 곱한 결과를 String.valueOf()로 문자열로 변환한 후, resBuilder의 맨 앞에 삽입한다.
예를 들어, 7 * 8 = 56이면 숫자 56 자체가 아니라 문자열 "56"이 resBuilder에 들어가게 된다.
이 부분이 "받아올림을 하지 않고 바로 결과에 적는" 규칙을 구현한 핵심이다.
i++: 다음 자릿수(왼쪽으로 한 칸 이동)로 넘어간다.
긴 문자열 남은 부분 처리:
while(i <= s1.length()) 루프는 s2의 모든 자릿수가 처리된 후, s1에 아직 남은 자릿수가 있을 경우에 실행된다.
resBuilder.insert(0, s1.charAt(s1.length() - i));: s1에 남아있는 자릿수(문자)를 그대로 resBuilder의 맨 앞에 삽입한다.
"자릿수가 짧은 수의 자리가 비어 있는 경우, 자릿수가 긴 수의 숫자만을 결과에 기록한다"는 규칙을 구현한 부분이다.
i++: 다음 자릿수로 넘어간다.
결과 반환:
모든 자릿수 처리가 끝나면 resBuilder에는 "잘못된 곱셈"의 결과가 문자열 형태로 담겨 있다.
Long.parseLong(resBuilder.toString()): 이 문자열을 최종적으로 long 타입의 숫자로 변환하여 반환한다.
if (resBuilder.length() == 0) { return 0; }: 만약 resBuilder가 비어있을 경우 발생할 수 있는 오류를 방지하기 위해 0을 반환한다.
코드로 구현
package baekjoon.baekjoon_31;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
// 백준 33557번 문제
public class Main1233 {
public static void main(String[] args) throws IOException { // throws Exception 대신 IOException
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine());
for (int t = 0; t < T; t++) {
StringTokenizer st = new StringTokenizer(br.readLine());
long A = Long.parseLong(st.nextToken());
long B = Long.parseLong(st.nextToken());
// 일반적인 곱셈 결과
long normalMultiplication = A * B;
// '잘못된 곱셈' 결과 계산
long wrongMultiplication = calculateWrongMultiplication(A, B);
// 두 결과가 같으면 1, 다르면 0 출력
sb.append(normalMultiplication == wrongMultiplication ? 1 : 0).append("\n");
}
System.out.println(sb);
br.close();
}
/**
* 문제에서 정의한 '잘못된 곱셈'을 계산하는 함수입니다.
* 원본 코드의 로직을 바탕으로 구현되었습니다.
* 이 방식은 두 숫자의 자릿수별 곱셈 결과를 문자열로 연결하고,
* 자릿수가 더 긴 쪽의 남은 숫자는 그대로 연결하는 방식입니다.
*
* @param A 첫 번째 정수
* @param B 두 번째 정수
* @return '잘못된 곱셈'의 결과값 (long)
*/
private static long calculateWrongMultiplication(long A, long B) {
String sA = String.valueOf(A);
String sB = String.valueOf(B);
// 항상 s1이 더 길거나 같은 길이의 문자열이 되도록 조정합니다.
String s1 = sA;
String s2 = sB;
if (sA.length() < sB.length()) {
s1 = sB;
s2 = sA;
}
StringBuilder resBuilder = new StringBuilder();
int i = 1;
// 짧은 문자열(s2)의 길이만큼 반복하며 각 자릿수를 곱하여 resBuilder에 삽입합니다.
// 이때, resBuilder.insert(0, ...)를 사용하여 결과를 역순으로 쌓아갑니다.
while (i <= s2.length()) {
// 오른쪽부터 i번째 자릿수 (charAt은 왼쪽부터 0-indexed이므로 길이에 i를 빼야 합니다)
int digit1 = s1.charAt(s1.length() - i) - '0';
int digit2 = s2.charAt(s2.length() - i) - '0';
// 두 자릿수를 곱한 결과를 문자열로 변환하여 맨 앞에 삽입 (예: 7*8=56 -> "56")
resBuilder.insert(0, String.valueOf(digit1 * digit2));
i++;
}
// 짧은 문자열(s2)이 끝난 후, 긴 문자열(s1)에 남은 자릿수들을 resBuilder에 삽입합니다.
while (i <= s1.length()) {
// 남은 자릿수를 문자로 가져와 맨 앞에 삽입 (예: '1')
resBuilder.insert(0, s1.charAt(s1.length() - i));
i++;
}
// 최종적으로 완성된 문자열을 long 타입으로 변환하여 반환합니다.
// 만약 resBuilder가 비어있다면(예외 처리), 0을 반환합니다.
if (resBuilder.length() == 0) {
return 0;
}
return Long.parseLong(resBuilder.toString());
}
}
코드와 설명이 부족할수 있습니다. 코드를 보시고 문제가 있거나 코드 개선이 필요한 부분이 있다면 댓글로 말해주시면 감사한 마음으로 참고해 코드를 수정 하겠습니다.