21번부터 30번까지 풀어보겠습니다. 모든 문제는 제가 직접 푼 풀이이며, 더 나은 풀이가 있다면 알려주세요~ 못 푼 문제는 끙끙대며 풀어볼테니 스포 금지!
Level 1 21번~30번
제일 작은 수 제거하기
[4,3,2,1]이 있다면 가장 작은 1을 제거해서 [4,3,2]를 리턴하면 됩니다.
필터링으로 간단하게 할 수 있을 것 같습니다.
function solution(arr) {
const min = Math.min(...arr);
const r = arr.filter(v => v !== min);
return r.length ? r : [-1];
}
하나 알아두시면 좋은 게 Math.min(...arr)
입니다. ...arr
은 배열을 펴서 넣는 것입니다. Math.min(arr[0], arr[1], arr[2], ...)
과 같습니다.
짝수와 홀수
function solution(num) {
return num % 2 ? 'Odd' : 'Even';
}
시간 아깝습니다.
최대공약수와 최소공배수
두 수의 최대공약수와 최소공배수를 구하는 함수입니다.
두 가지를 알아두시는 게 좋은데 바로 최대공약수를 구하는 유클리드 호제법과, 두 수의 곱은 최대공약수와 최소공배수의 곱과 같다는 점입니다. 아니 이걸 어떻게 아냐고요? 여러분 모두 중학교 때 배웠습니다...
function solution(n, m) {
function u(n, m) { return m % n ? u(m % n, n) : n; }
const gcd = u(n, m);
return [gcd, n * m / gcd];
}
u가 유클리드 호제법 함수입니다. 재귀식으로 작성되어 있고요(만약 꼬리재귀가 나중에 된다면 u(m % n, n)
을 뒤에 둬야겠죠?). gcd(greatest common divisor)가 최대공약수입니다. 최소공배수는 아까 알려드린 공식대로 구하면 됩니다.
콜라츠 추측
입력된 수가 짝수면 2로 나누고, 홀수면 3을 곱한 후 1을 더합니다. 이 작업을 반복해서 1까지 몇 번만에 나오는지 구해야 합니다. 6의 경우 6 -> 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1로 8번 만에 1이 됩니다. 500회 반복해도 안 되는 경우 -1을 리턴합니다.
일단 조건이 크게 세 개입니다. 500회 반복 초과 경우와, 홀수인 경우, 짝수인 경우입니다. 500회 반복 초과만 별도 처리하고 다른 건 재귀식으로 하면 될 것 같습니다.
function solution(num, count = 0) {
return count === 500
? -1
: num === 1
? count
: solution(num % 2 ? num * 3 + 1 : num / 2, count + 1);
}
재귀를 사용하면 반복 작업을 줄일 수 있어 편합니다.
평균 구하기
function solution(arr) {
return arr.reduce((a, c) => a + c) / arr.length;
}
평균, 곱, 합 등등 뭔가 쌓이는 것들은 다 reduce로 하면 깔끔합니다.
하샤드 수
x의 자릿수의 합으로 x가 나눠 떨어지면 x는 하샤드 수입니다. 18의 자리수의 합은 1 + 8 = 9이고, 18은 9로 나눠 떨어지므로 18은 하샤드 수인거죠.
일단 자릿수를 쪼개서 더하는 것부터 합시다. split과 reduce면 되죠.
function solution(x) {
return !(x % String(x).split('').reduce((a, c) => a + c * 1, 0));
}
x를 나눌 수 있으면 0(falsy value)가 나오기 때문에 앞에 !를 붙여 true로 만들었습니다. 문자열을 숫자로 만들기 위해 이번에는 * 1을 한 번 붙여봤습니다. parseInt도 있고 +도 있고 / 1도 있고 다양하게 문자열을 숫자로 만들 수 있습니다.
핸드폰 번호 가리기
전화번호 뒷 4자리를 빼고 나머지를 전부 *로 바꾸는 문제입니다. 뒷 네자리를 떼내고 앞은 다 *로 바꾼 뒤 다시 붙이면 되겠죠?
function solution(phone_number) {
return '*'.repeat(phone_number.length - 4) + phone_number.slice(-4);
}
repeat 메서드를 알아두세요. 문자열을 쉽게 반복할 수 있습니다.
정규표현식으로 하면 더 간단하더군요 ㅠㅠ (?=)로 look behind를 썼네요.
function solution(s) {
return s.replace(/\d(?=\d{4})/g, "*");
}
행렬의 덧셈
[[1,2],[2,3]]과 [[3,4],[5,6]]이 있으면 [[4,6],[7,9]]가 됩니다. 끼리끼리 더하면 됩니다.
2차원 배열이기 때문에 반복문이 두 번 필요합니다. for을 안 쓰기로 했기 때문에 map을 두 번 연달아 쓰면 됩니다. map을 쓰는 이유는 1,2가 4,6으로, 2,3이 7,9로 1대1로 바뀌기 때문입니다.
function solution(arr1, arr2) {
return arr1.map((arr, i) => arr.map((v, j) => v + arr2[i][j]));
}
x만큼 간격이 있는 n개의 숫자
x의 배수를 n개 나열하면 됩니다. 2와 5면 [2,4,6,8,10]이고 -4와 2면 [-4,-8]입니다.
Array fill map을 사용하면 숫자로부터 배열을 쉽게 만들 수 있습니다.
function solution(x, n) {
return Array(n).fill(x).map((v, i) => (i + 1) * v)
}
map으로 원래의 수와 배수를 1대1로 짝지어주면 됩니다.
직사각형 별찍기
자바스크립트 문제로는 없어서 그냥 제가 직접 풀었습니다. 왜 안 만들었는지 모르겠네요. 5와 3이 주어지면 5열3행의 별을 찍으면 됩니다.
function solution(a, b) {
return Array(b).fill().map(() => '*'.repeat(a)).join('\n');
}
\n이 줄바꿈 표시이기때문에 별들로 먼저 배열을 만들고 요소들 사이에 줄바꿈을 넣어줍니다.
다음 시간부터는 Level 2 문제를 풉니다. Level 1보다 확실히 어렵고, 같은 Level 2끼리도 난이도 편차가 좀 있더군요. 노력해보겠습니다!