백준 곱셈을 누가 이렇게 해 ㅋㅋ

KIMYEONGJUN·2025년 12월 11일
post-thumbnail

문제

내가 생각했을때 문제에서 원하는부분

총 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());
    }
}

마무리

코드와 설명이 부족할수 있습니다. 코드를 보시고 문제가 있거나 코드 개선이 필요한 부분이 있다면 댓글로 말해주시면 감사한 마음으로 참고해 코드를 수정 하겠습니다.

profile
Junior backend developer

0개의 댓글