백준

[백준] 1676 팩토리얼 0의 개수_ JAVA

채니◟( ˘ ³˘)◞ 2023. 6. 9. 15:47

● 문제


● 풀이

 

10! = 10×9×8×...×2×1 = 3,628,800

 

뒤에서부터 8 전까지 0의 개수가 2개이므로 출력은 2이다.

 

내가 생각한 풀이는

팩토리얼 값을 구한뒤 문자열로 변환해서 뒤에서부터 문자열이 0이면 카운트 세는 것이다.


첫번째 풀이 ( 오류 )

이유 : int값으로 팩토리얼 계산 값을 받아왔는데, 특정 이상 수의 값이 int 범위를 초과한다.

해결 방법 : BigInteger 클래스 사용

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

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

        int N = in.nextInt();

        String num = Integer.toString(factorial(N));

        int cnt = 0;

        //num의 인덱스는 0부터 시작하므로 가장 오른쪽 문자의 인덱스는 num.length()-1 이다.
        for(int i = num.length()-1; i >= 0; i--){
            if(num.charAt(i) == '0'){
                cnt ++;
            }else
                break;
        }
        System.out.println(cnt);

    }
    static int factorial(int n){
        if (n == 1 || n == 0)
            return 1;
        return n * factorial(n-1);
    }
}

두 번째 풀이 (성공)

위에서 오류를 잡아 BigInteger 클래스를 사용하여 코드를 변환하였다.

백준 풀이는 성공하였지만, 이 코드의 문제는 입력 값이 커질 경우 스택 오버플로우가 발생할 수도 있다는 점이다.

import java.math.BigInteger;
import java.util.Scanner;

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

        int N = in.nextInt();

        BigInteger factorial = factorial(N);
        String num = factorial.toString();

        int cnt = 0;

        for (int i = num.length() - 1; i >= 0; i--) {
            if (num.charAt(i) == '0') {
                cnt++;
            } else {
                break;
            }
        }
        System.out.println(cnt);
    }

    static BigInteger factorial(int n) {
        if (n == 0 || n == 1) {
            return BigInteger.ONE;
        }
        return BigInteger.valueOf(n).multiply(factorial(n - 1));
    }
}

그래서 더 최적화된 코드를 찾기 위해 구글링을 해보았다.

(출처 : https://st-lab.tistory.com/165)

 

매우 간단한 코드가 있었다.... 박탈감이 든다........

import java.util.Scanner;
 
public class Main {
 
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
 
		int num = in.nextInt();
		int count = 0;
 
		while (num >= 5) {
			count += num / 5;
			num /= 5;
		}
		System.out.println(count);
	}
 
}

 코드 설명

위 팩토리얼를 보면 규칙이 있다.

 

뒷자리가 0이 나오는 경우는 2와 5가 곱해져 있을 때이고, 거꾸로 말하자면 소인소분해를 해서 2와 5가 존재할 경우 0으로 끝나는 것이다.

위 표를 보면 5의 배수마다 0의 카운트 값이 증가하는 것을 볼 수 있다.

 

그런데 25일 때 카운트값이 1이 아닌 2가 증가한다.

그래서 단순히 5로 나누는 것이 아니라 반복문을 통해 5로 나누면서 누적합을 해주어야한다.