이 영역을 누르면 첫 페이지로 이동
Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

프로그래밍과 관련하여 다양한 알고리즘 문제를 풀어보고, 프로그래밍 언어를 이해해 볼 수 있도록 돕고자 만든 블로그 입니다.

[백준] 1929번 : 소수 구하기 - JAVA [자바]

  • 2020.04.21 14:04
  • JAVA - 백준 [BAEK JOON]/기본 수학 2
글 작성자: ST_
728x90





https://www.acmicpc.net/problem/1929

 

1929번: 소수 구하기

첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.

www.acmicpc.net








  • 문제

 

 

 


이번 문제는 에라토스테네스의 체를 이용하여 풀어보는 정석적인 문제다!

알고리즘 분류에도 에라토스테네스의 체로 분류되어 있다.

 








  • 4가지 방법을 이용하여 풀이한다.



문제를 들어가보면 알겠지만 알고리즘 분류에도 에라토스테네스의 체로 분류되어있는만큼 해당 알고리즘으로 풀어볼 것이다.

 

소수를 구하는 방법은 여러가지가 있지만 에라토스테네스의 체가 가장 대중적이면서 알고리즘 효율이 매우 좋은편인 방법이다.

소수를 구하는 방법에 대해 좀 더 자세히 알아보고자 하면 아래 포스팅을 참고하시라

 

https://st-lab.tistory.com/81

 

소수를 구하는 알고리즘 - JAVA [자바]

들어가기 전에 소수 [Prime Number] 소수의 정의는 1보다 큰 자연수 중 1 과 그 수 자기 자신만을 약수로 갖는 자연수를 의미한다는 점은 누구나 알고 있을 것이다. 즉, 소수의 약수는 2개만을 갖고, 그 중 하나는..

st-lab.tistory.com

 

 

입력은 Scanner 와 BufferedReader 을 통한 방법과 출력 방법, 마지막으로 약간 변형하여 다른 방식으로 접근한 방법까지 같이 알아보고자 한다.

 




  • 풀이




- 방법 1 

 

import java.util.Scanner;


public class Main {
	public static boolean[] prime;
	public static void main(String[] args) {

		Scanner in = new Scanner(System.in);
		int M = in.nextInt();
		int N = in.nextInt();
		
		prime = new boolean[N + 1];
		get_prime();
				
		for(int i = M; i <= N; i++) {
			// false = 소수 
			if(!prime[i]) System.out.println(i);
		}
	}


	// 에라토스테네스의 체 알고리즘
	public static void get_prime() {
		// true = 소수아님 , false = 소수 
		prime[0] = prime[1] = true;
		
		for(int i = 2; i <= Math.sqrt(prime.length); i++) {
			if(prime[i]) continue;
			for(int j = i * i; j < prime.length; j += i) {
				prime[j] = true;
			}
		}
	}
}

 

 

가장 기본적인 방법이라 할 수 있겠다.

 

위의 알고리즘에 대한 자세한 설명은 앞서 참고하라던 포스팅에서 자세하게 다루니 원리를 이해하기 힘들다면 꼭 읽어보길 바란다.








- 방법 2 

 


그런데 출력 할 소수가 많아서 출력 호출 횟수가 많아질 수 있으니 조금이나마 성능을 개선하기 위해 하나의 문자열로 연결시킨다음 한 번에 출력시키도록 변경 할 수도 있다.

 

이 때는 StringBuilder 을 사용하면 되겠다.

 

import java.util.Scanner;


public class Main {
	public static boolean[] prime;
	public static void main(String[] args) {

		Scanner in = new Scanner(System.in);
		int M = in.nextInt();
		int N = in.nextInt();
		
		prime = new boolean[N + 1];
		get_prime();
				
		StringBuilder sb = new StringBuilder();
		for(int i = M; i <= N; i++) {
			// false = 소수 
			if(!prime[i]) sb.append(i).append('\n');
		}
		System.out.println(sb);
	}


	// 에라토스테네스의 체 알고리즘
	public static void get_prime() {
		// true = 소수아님 , false = 소수 
		prime[0] = prime[1] = true;
		
		for(int i = 2; i <= Math.sqrt(prime.length); i++) {
			if(prime[i]) continue;
			for(int j = i * i; j < prime.length; j += i) {
				prime[j] = true;
			}
		}
	}
}









- 방법 3 

 

 

BufferedReader 을 사용하는 방법이다. 

알고리즘 자체는 앞선 방법들이랑 똑같고, 다만 입력방법만 달리 할 뿐이다.

 

이때 문자열 분리를 위해 StringTokenizer 을 쓸 것이다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;


public class Main {
	public static boolean[] prime;
	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine()," ");
		int M = Integer.parseInt(st.nextToken());
		int N = Integer.parseInt(st.nextToken());
		
		prime = new boolean[N + 1];
		get_prime();
		
		StringBuilder sb = new StringBuilder();
		
		for(int i = M; i <= N; i++) {
			// false = 소수 
			if(!prime[i]) sb.append(i).append('\n');
		}
		System.out.println(sb);
	}

	public static void get_prime() {
		// true = 소수아님 , false = 소수 
		prime[0] = prime[1] = true;
		
		for(int i = 2; i <= Math.sqrt(prime.length); i++) {
			if(prime[i]) continue;
			for(int j = i * i; j < prime.length; j += i) {
				prime[j] = true;
			}
		}
	}
}

 








- 방법 4



방법 3 에서 굳이 소수 배열 따로, 검사 따로 하는 방법이 아니라 소수인지 아닌지 판별과 동시에 소수라면 바로 그 변수를 출력하는 방법이 있다.

 

다만, 이 방법은 첫 반복문이 Math.sqrt(), 즉 최댓값의 제곱근까지만 순회하는 것이 아니라 최댓값까지 계속 순회해야 가능하다.

또한, 이중 반복문의 내부 반복문은 int j = i * i 을 할 경우 입력 최댓값이 1,000,000 이라 i 가 최대 1,000,000 가 된다면 j 의 경우 1,000,000,000,000 으로 int 형 범위를 넘어버릴 수 있어 int j = i + i 로 변경하여 풀어야 한다.

 

위 두가지 사항만 고려하면 아래와 같이 변경할 수 있다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        StringTokenizer st = new StringTokenizer(br.readLine()," ");
        int M = Integer.parseInt(st.nextToken());
        int N = Integer.parseInt(st.nextToken());
        
        boolean[] prime = new boolean[N + 1];
        
        for(int i = 2; i <= N; i++) {
        	if(prime[i]) continue;
        	
        	if(i >= M) sb.append(i).append('\n');
        	
        	for(int j = i + i; j <= N; j += i) {
        		prime[j] = true;
        	}
        }
        
        System.out.println(sb);
    }

}



 








  • 성능





위에서 부터 순서대로

 

채점 번호 : 19298058  -  BufferedReader (방법 4)

채점 번호 : 19297971  -  BufferedReader (방법 3)

채점 번호 : 19297933  -  Scanner + StringBuilder (방법 2)

채점 번호 : 19297874  -  Scanner + System.out.println (방법 1)

 

 

보다시피 입력방법과 출력 방법에 따라서도 성능차이가 많이 난다.








  • 정리

 


에라토스테네스의 체를 이용한 방법을 제대로 쓴 문제다.

 

이후 문제들 중에서도 소수를 구하는 문제들이 얼마나 있을지는 모르겠지만, 적어도 에라토스테네스의 체를 완벽히 이해하는 계기가 되었으면 한다.

 

고로 참고하라고 하는 포스팅을 꼭 읽어보았으면 좋겠다.





저작자표시 비영리 변경금지 (새창열림)

'JAVA - 백준 [BAEK JOON] > 기본 수학 2' 카테고리의 다른 글

[백준] 11653번 : 소인수분해 - JAVA [자바]  (0) 2021.01.09
[백준] 9020번 : 골드바흐의 추측 - JAVA [자바]  (16) 2020.05.05
[백준] 4948번 : 베르트랑 공준 - JAVA [자바]  (14) 2020.04.24
[백준] 2581번 : 소수 - JAVA [자바]  (20) 2020.04.21
[백준] 1978번 : 소수 찾기 - JAVA [자바]  (20) 2020.04.08

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [백준] 9020번 : 골드바흐의 추측 - JAVA [자바]

    [백준] 9020번 : 골드바흐의 추측 - JAVA [자바]

    2020.05.05
  • [백준] 4948번 : 베르트랑 공준 - JAVA [자바]

    [백준] 4948번 : 베르트랑 공준 - JAVA [자바]

    2020.04.24
  • [백준] 2581번 : 소수 - JAVA [자바]

    [백준] 2581번 : 소수 - JAVA [자바]

    2020.04.21
  • [백준] 1978번 : 소수 찾기 - JAVA [자바]

    [백준] 1978번 : 소수 찾기 - JAVA [자바]

    2020.04.08
다른 글 더 둘러보기

정보

Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

  • Stranger's LAB의 첫 페이지로 이동

검색

나의 외부 링크

  • st-github

공지사항

  • 공지 - 블로그 사용 설명서

메뉴

  • 홈
  • 방명록

카테고리

  • 전체 카테고리 (267)
    • Java (5)
    • JAVA - 백준 [BAEK JOON] (177)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (10)
      • 기본 수학 1 (8)
      • 기본 수학 2 (6)
      • 2차원 배열 (0)
      • 정렬 (10)
      • 재귀 (4)
      • 브루트 포스 (5)
      • 집합과 맵 (0)
      • 기하 1 (5)
      • 정수론 및 조합론 (12)
      • 백트래킹 (8)
      • 동적 계획법 1 (15)
      • 누적 합 (0)
      • 그리디 알고리즘 (5)
      • 스택 (5)
      • 큐, 덱 (7)
      • 분할 정복 (9)
      • 이분 탐색 (7)
      • 기타 문제 (17)
      • 별 찍기 문제 모음 (2)
    • C++ - 백준 [BAEK JOON] (46)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (0)
      • 기타 문제 (4)
    • 자료구조 (18)
      • Java (18)
    • 알고리즘 (11)
      • Java (11)
    • 프로그래밍 기초 (6)
    • 이모저모 (2)
    • 일상의 글 (2)

최근 글

정보

ST_의 Stranger's LAB

Stranger's LAB

ST_

블로그 구독하기

  • 구독하기
  • 네이버 이웃 맺기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © ST_.

티스토리툴바