비슷한 문제끼리 묶어서 풀이합니다.
개별 풀이는 주석 참고 부탁드립니다.
function sumTo(num) {
/*
1. num => num
2. base: num === 0
3. recursive: num + sumTo(num-1)?
*/
if (num === 0) return 0;
return num + sumTo(num - 1);
}
/////
function factorial(num) {
/*
1. num => num
2. base: num === 0
3. recursive: num * factorial(num - 1)
*/
if (num === 0) return 1;
return num * factorial(num - 1);
}
/////
function fibonacci(num) {
/*
1. num => num
2. base: num <= 1
3. recursive: fibonacci(num - 2) + fibonacci(num - 1)
*/
if (num <= 1) return num;
return fibonacci(num - 2) + fibonacci(num - 1);
}
세 문제 모두 memoization 이 금지됩니다.
입출력값은 num => num 으로 정의되고,
각 함수는 기본 사례(base case)와 재귀 사례(recursive case)로 구성됩니다.
base
입력이 조건을 만족할 때 함수가 바로 결과값을 반환하도록 합니다.
recursive
입력을 더 작은 부분 문제로 나누고,
함수를 자기 자신에게서 호출하여 더 작은 부분 문제를 해결합니다.
조건문과 재귀로만 해결할 수 있는 문제입니다.
function drop(num, arr) {
/*
1. num, [arr] => [arr.length - 3]
2. base: arr.length <= num or num === 0
3. recursive: drop(num-1, arr)
*/
if (arr.length <= 0) return [];
else if (num === 0) return arr;
arr.shift(); // 미리 빼 줘야 함
return drop(num-1, arr);
}
/////
function take(num, arr) {
/*
1. num, [arr] => sliced arr
2. base: arr.length <= num
3. recursive: result.pop 후 take(num, result);
*/
if (arr.length <= num) return arr;
let result = arr.slice();
result.pop();
return take(num, result);
}
입출력 값: num, [arr] => [arr]
base
조건에 따라 배열의 일부 또는 전체, 또는 []을 반환
recursive
새 배열을 생성, 기존 배열을 수정 후 재귀
재귀하며 배열이 변형되고, 기본 사례에 도달할 때까지 반복 실행됩니다.
재귀와 배열 요소 제거 메서드를 사용해 해결하는 문제입니다.
function reverseArr(arr) {
/*
1. [some] => [emos]
2. base: arr.length < 1
3. recursive: reverseArr(arr.slice(1번째))로 재귀하면서
.concat(arr.shift())
*/
if (arr.length === 0) return [];
return reverseArr(arr.slice(1)).concat(arr.shift());
}
배열을 뒤집는 문제입니다.
base
주어진 배열의 길이가 0일 때 빈 배열을 반환
재귀를 멈추고 배열을 뒤집어 재구성
recursive
0번째 요소를 제거한 arr.slice(1)을 재귀 함수로 전달
이후 제거된 요소는 arr.shift()로 리턴
해당 요소를 concat -> 재귀 결과에 결합
다시 돌아가며 배열 재구성
function findMatryoshka(matryoshka, size) {
/*
1. {{{...}}} => boolean
2. base: Object.keys(mat).length === 0
3. recursive: mat.size, 재귀: fmk(mat.mat, size);
*/
// 탈출 조건
if (Object.keys(matryoshka).length === 0) return false;
// 첫 객체에서 같으면 나오기
else if (matryoshka.size === size) return true;
// 받은 객체에 없으면 내부 객체 있는지 확인, 내부 객체로 재귀
else if (matryoshka.matryoshka && matryoshka.size)
return findMatryoshka(matryoshka.matryoshka,size);
// 위에서 다 없으면 false
else return false;
}
base
마트료시카의 속성 개수가 0일 때 return false
= 재귀 종료, 같은 size 없음
recursive
현재 마트료시카의 크기와 입력받은 크기가 일치하는지 확인
1-1. 일치하면 true, 재귀 종료
1-2. 일치하지 않는 경우 -> 2
현재 마트료시카 객체에 내부 마트료시카 객체(mat.mat) 유무와
크기(mat.size)를 확인
2-1. 내부 마트료시카 객체로 재귀
내부 마트료시카를 검사하고 크기가 일치하는 객체를 찾을 때까지 탐색
내부 객체가 없거나 크기가 일치하는 객체를 찾지 못하면 false
function unpackGiftbox(giftBox, wish) {
/*
1. [..[..]] => boolean
2. base: let el of giftBox에 대한 반복문 종료 시
3. recursive: unpackGiftbox(el, wish)
*/
let count = 0; // 있으면 카운트해서 대소비교로 boolean 리턴
for (let el of giftBox) {
if (Array.isArray(el)) { // 2차원 배열 있을 때
count += unpackGiftbox(el, wish); // 배열 없을 때까지 재귀
} else if (el === wish) count++;
// 배열 없으면 wish 찾으면서 count하며 밖으로 나가기
}
return count > 0;
}
/////
function flattenArr(arr) {
// TODO: 여기에 코드를 작성합니다.
/*
1. [[[...]]] => []
2. base: let element of arr에 대한 반복문 종료 시
3. recursive: flattenArr(element)로 재귀하면서
새 변수에 el을 추가해야 함 (배열: concat, else: push)
*/
let flattened = [];
for (let element of arr) {
if (Array.isArray(element)) {
flattened = flattened.concat(flattenArr(element));
} else flattened.push(element);
}
return flattened;
}
base
배열 안에 더 이상 다른 배열이 없을 때
-> 작업 수행, 결과 반환
recursive