코테 및 알고리즘

백준 js 4948번

Jay_Jung 2024. 7. 2. 16:57

 

<문제>

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

 

 

 

 

<문제 핵심>

1. 에라스토텔레스의 체

개념: 소수를 판별하는 알고리즘으로 소수들을 대량으로 빠르고 정확하게 구하는 방법이다. 에라토스테네스의 체는 가장 먼저 소수를 판별할 범위만큼 배열을 할당하고 인덱스에 해당하는 값을 비교하여 범위에 해당하는 소수를 빠르게 찾아낸다. 즉 소수의 배수를 제거하여 소수가 아닌 것들을 제거하고 소수로만 구성되어 있는 배열을 만들 수 있다.

 

 

<문제 풀이과정 및 순서도>

1. 입력받은 후 inputs의 마지막 요소인 0을 제거한다.

let inputs = require("fs")
  .readFileSync(process.platform === "linux" ? "/dev/stdin" : "./input.txt")
  .toString()
  .trim()
  .split("\n")
  .map(Number);

inputs.pop(); // 0 제거

 

 

2. 에라토스테네스의 체 알고리즘을 한 번만 실행하여 모든 테스트케이스의 소수를 미리 계산하기 위해서 inputs 배열 중 최대값을 선택하고 *2배 만큼의 범위를 설정한다. 여러번 모든 소수를 계산하는 것이 아닌 한 번에 모든 소수를 계산하는 것이다. 이후 설정한 범위만큼 배열을 채우고 0과 1은 소수가 아니기 때문에 false로 설정한다.

let maxInput = Math.max(...inputs);
let maxRange = maxInput * 2;
//예를 들어 입력값이 30인 경우 -> 60까지의 소수임을 판별하는 배열 생성
let isPrimeNumber = Array(maxRange + 1).fill(true);
isPrimeNumber[0] = isPrimeNumber[1] = false;

 

3. 2부터 시작하여, 해당 숫자가 소수인지 확인한다. 그 숫자가 소수라면, 그 숫자의 배수를 모두 제거한다.

 

for (let i = 2; i <= Math.ceil(Math.sqrt(maxRange)); i++) {
  if (isPrimeNumber[i]) {
    for (let j = i * i; j <= maxRange; j += i) {
      isPrimeNumber[j] = false;
    }
  }
}

 

4. input + 1부터 input * 2까지의 범위를 순회하는데 즉 각 숫자마다 범위에 맞춰서 소수가 있는지를 판단하고 있으면 count를 증가시켜준다. 이후 모든 입력값에 대한 순회를 마친 후 줄바꿈을 적용하며 출력한다.

let results = inputs.map((input) => {
  let count = 0;
  for (let i = input + 1; i <= input * 2; i++) {
    if (isPrimeNumber[i]) {
      count++;
    }
  }
  return count;
});

console.log(results.join("\n"));

<전체 코드>

let inputs = require("fs")
  .readFileSync(process.platform === "linux" ? "/dev/stdin" : "./input.txt")
  .toString()
  .trim()
  .split("\n")
  .map(Number);

inputs.pop(); // 0 제거

let maxInput = Math.max(...inputs);
let maxRange = maxInput * 2;

//예를 들어 입력값이 30인 경우 -> 60까지의 소수임을 판별하는 배열 생성
let isPrimeNumber = Array(maxRange + 1).fill(true);
isPrimeNumber[0] = isPrimeNumber[1] = false;

for (let i = 2; i <= Math.ceil(Math.sqrt(maxRange)); i++) {
  if (isPrimeNumber[i]) {
    for (let j = i * i; j <= maxRange; j += i) {
      isPrimeNumber[j] = false;
    }
  }
}

let results = inputs.map((input) => {
  let count = 0;
  for (let i = input + 1; i <= input * 2; i++) {
    if (isPrimeNumber[i]) {
      count++;
    }
  }
  return count;
});

console.log(results.join("\n"));