문제
약수의 개수가 세 개 이상인 수를 합성수라고 합니다. 자연수 n이 매개변수로 주어질 때 n이하의 합성수의 개수를 return하도록 solution 함수를 완성해주세요.
제한사항
- 1 ≤ n ≤ 100
입출력 예
n | result |
10 | 5 |
15 | 8 |
입출력 예 #1
- 10 이하 합성수는 4, 6, 8, 9, 10 로 5개입니다. 따라서 5를 return합니다.
입출력 예 #2
- 15 이하 합성수는 4, 6, 8, 9, 10, 12, 14, 15 로 8개입니다. 따라서 8을 return합니다.
내가 작성한 답안
function solution(n) {
// 1부터 n까지의 수를 배열에 담는다.
let arr = [];
for(let i = 1; i <= n; i++) arr.push(i);
// 각 요소가 합성수인지 판별한 뒤 합성수면 sum값을 1 증가시킨다.
let sum = 0;
for(let i of arr) if(isNotPrime(i) === true) sum++;
// 결과값을 return한다.
return sum;
}
// 합성수인지(소수가 아닌지) 판별하는 함수
function isNotPrime(num) {
let divisor = [];
// num의 약수를 담는다.
for(let i = 1; i <= num; i++) if(num % i === 0) { divisor.push(i); }
// divisor의 길이가 3 이상이면 (합성수이면) true를 리턴한다.
return divisor.length >= 3 ? true : false;
}
다른 사람들이 작성한 답안
function solution(n) {
let base = Array.from(Array(n), (v,i) => i+1)
for(let i = 2; i <= parseInt(Math.sqrt(n)); i++) {
base = base.filter(el => el%i != 0 || el <= i)
}
return n - base.length
}
위의 코드를 눈으로만 봤을 때 아직 한 번에 코드 파악이 되지 않아, 내가 이해할 수 있도록 한 줄씩 콘솔로 찍어보면서 그 의미를 정리했다.
let base = Array.from(Array(n), (v,i) => i+1);
Array.from(Array(n), (v,i) => v)만 콘솔로 찍었을 때는 undefined가 나왔고, Array.from(Array(n), (v,i) => i)만 콘솔로 찍었을 때는 0부터 n-1까지의 숫자가 배열에 담겼다.
따라서 Array.from(Array(n), (v,i) => i+1)은 1부터 n까지의 수를 변수에 배열로 담는 것!
빈 배열을 선언하고 for문을 돌려 i를 push하는 경우에는 두 줄로 작성해야 했지만 위와 같은 경우는 한 줄로 표현이 가능하다. 뭐가 더 나은 방법일까? 다만 for문, push(i)는 많이 사용해 봤으니 위의 방법을 쓰면서 손에 익도록 연습해 봐야겠다.
for(let i = 2; i <= parseInt(Math.sqrt(n)); i++) {
base = base.filter(el => el%i != 0 || el <= i)
}
for문 조건식의 경우
1) 1은 소수가 아니므로 i의 초기값에서 제외한다.
2-1) n이 제곱근값으로 나누어 떨어진다면 √n의 배수라는 뜻이므로 소수가 아니게 된다. (ex. 25의 제곱근은 √25 = 5) 따라서 √n까지만 반복문이 돌아가더라도 소수가 아님은 판별할 수 있으므로 i를 Math.sqrt(n)까지로 둔다.
2-2) √n의 값이 정수가 아닌 유리수가 나올 수 있으므로 parseInt를 사용하여 정수를 반환할 수 있도록 한다.
반복문 안의 base 재할당 filter 조건식은 1부터 n까지의 수가 순차적으로 담겨있는 배열 base에서
1) 각 요소(el)를 i로 나눴을 때의 나머지값이 0이 아니거나 (약수이거나)
2) i가 각 요소(el)보다 같거나 클 경우
두 가지 값을 담아 base에 다시 새로운 배열을 return한다.
예를 들어 n이 10일 때,
- base.filter(el => el%i != 0)만 진행했을 때의 출력값 [1, 5, 7]
- base.filter(el => el <= i)만 진행했을 때의 출력값 [1, 2]
- 둘을 공통적으로 돌렸을 때 나오는 출력값 [1, 2, 3, 5, 7]
따라서 base.filter(el => el%i != 0 || el <= i)은 n 이하의 소수만 배열로 반환한다!
return n - base.length
n에서 소수만 담겨있는 배열 base의 길이만큼의 수를 제한다. 최종적으로 n 이하의 합성수 개수만 return 한다.
Array.from()
ES6에 새로 추가된 문법으로, 유사 배열 객체나 반복 가능한 객체를 얕게 복사해 새로운 Array 객체를 만든다.
Array.from(arrayLike[, mapFn[, thisArg]])
- arrayLike : 배열로 변환하고자 하는 유사 배열 객체나 반복 가능한 객체 즉, 배열로 만들 이터러블한 객체
- mapFn : 생성한 배열의 모든 원소에 대해 수행할 맵핑 함수
- thisArg : mapFn 실행 시 this로 사용할 값
parseInt()
첫 번째 인자를 문자열로 변환하고, 그 값을 파싱하여 정수나 NaN을 반환한다.
parseInt(string[, radix])
- string : 파싱할 값으로, 문자열이 아닐 경우 toString을 이용해 문자열로 변환한다.
- radix : string의 진수를 나타내는 2~36의 정수다. 단, 기본값이 10이 아님을 주의해야 한다.
[반환값]
1. 주어진 string에서 파싱한 정수를 반환한다.
console.log(parseInt('2입니다')); // 2
console.log(parseInt('-1입니다')); // -1
console.log(parseInt('3-1')); // 3
2. NaN을 반환한다.
a. radix가 2보다 작거나 36보다 큰 경우
b. 공백이 아닌 첫 문자를 숫자로 변환할 수 없는 경우
Math.sqrt()
함수의 제곱근을 반환한다.
Math.sqrt(x)
- x : 숫자
[반환값]
주어진 숫자에 루트를 씌워 반환하는데, 숫자가 음수이면 NaN을 반환한다.
[참고 자료]
https://school.programmers.co.kr/learn/courses/30/lessons/120846
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/parseInt
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt
'Front-End > Algorithm' 카테고리의 다른 글
[프로그래머스 / JavaScript] Lv.1 행렬의 덧셈 (3) | 2023.04.10 |
---|---|
[프로그래머스 / JavaScript] Lv.1 핸드폰 번호 가리기 (0) | 2023.04.08 |
[프로그래머스 / JavaScript] Lv.1 두 개 뽑아서 더하기 (0) | 2023.03.16 |
[프로그래머스 / JavaScript] Lv.0 제곱수 판별하기 (0) | 2023.02.21 |
[프로그래머스 / JavaScript] Lv.1 문자열 내 마음대로 정렬하기 (0) | 2023.02.15 |