백준 1676: 팩토리얼 0의 개수
문제 설명
N!에서 뒤에서부터 처음 0이 아닌 숫자가 나올 때까지 0의 개수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N이 주어진다. (0 ≤ N ≤ 500)
출력
첫째 줄에 구한 0의 개수를 출력한다.
제출 코드
실행속도 : 64ms
메모리 : 11512KB

숫자 끝에 0이 붙으려면 어떤 수에 10을 곱해야 한다는 것이 포인트
그렇다면, 팩토리얼 에서 10이 곱해지는 경우는 2*5뿐이다 (10도 2*5 쌍이라고 볼 수 있다)
따라서 N!에서 끝 0의 개수는?
1부터 N까지 모든 수를 소인수분해했을 때 2,5 짝의 개수를 구하면 됨.
여기서 2의 개수는 2, 4, 8 ... 로 5의 개수보다 확실히 많으므로,
=> 결국 5의 개수를 세면 된다!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int zeroCount = 0;
for (int i=5; i<=N; i+=5) {
// 5로 나눠지는 횟수만큼 0 개수 추가
zeroCount += countFive(i);
}
System.out.println(zeroCount);
}
private static int countFive(int i) {
int count = 0;
while (i % 5 == 0) {
i /= 5;
count += 1;
}
return count;
}
}
5의 개수만 세면 되므로, 5부터 N까지 i를 5씩 증가시키며 5의 배수일 때만
countFive 메서드를 만들어 5의 수를 세었다.
개선 코드
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int zeroCount = 0;
// 5의 배수마다 5의 개수를 더함
for (int i = 5; i <= n; i *= 5) {
zeroCount += n / i;
}
System.out.println(zeroCount);
}
}
- i를 5씩 증가시키는 대신, 5의 제곱 배수를 한 번에 처리했다.
이를 통해 5, 25, 125 등에서 각각 추가로 생기는 5의 개수를 누적할 수 있다. - 기존 코드는 i를 5씩 증가시켜 시간복잡도가 O(N/5* log₅N) 인 반면,
이 방식은 i를 5씩 곱해주며 시간 복잡도를 O(log₅N)으로 최적화할 수 있었다!
깨달은 점
기존 코드도 충분히 효율적인 코드라고 느껴져 더 개선할 점이 있을까 생각했는데,
5의 개수를 구하는 과정에서 5의 지수마다 변곡점이 생기므로, 5씩 곱해주며 계산할 수 있는 방법이 있다는 것에 놀랐다.
언제나 더 효율적인 코드는 존재한 다는 것을 다시 한번 느낀다.