수(num)를 입력받아 1부터 num까지의 합을 리턴해야 합니다.
function sumTo(num) {
// base case -> num === 0
// 0 + sumTo(num-1)
return num === 0 ? 0 : num + sumTo(num-1)
}
물론 base case와 따로 처리해도 상관없는데
그냥 if - else 로 하고 보니 삼항연산자를 이용해야겠다 싶어서 이용..해도 되려나? 했는데 돼서 그냥 됐다 ! 됐어!🤪
수를 입력받아 홀수인지 여부를 리턴해야 합니다.
function isOdd(num) {
// num > 0 => num에 계속 -2를 해주어서 0이 되면 짝수(false), 1이 되면 홀수(true)
// num < 0 => num에 계속 +2를 해주어서 0이 되면 짝수(false), 1이 되면 홀수(true)
// -17도 홀수, -40도 짝수 (음수에도 짝수 홀수가 있음!)
if (num === 0) return false // base case
if (num === 1) return true // base case
if (num < 0) {
return isOdd(num + 2)
}
if (num > 0) {
return isOdd(num - 2)
}
}
처음에 약간 오잉..? 싶었음
항상 -2 를 반복해서 빼주는 것이 더 익숙하던 (반복문) 나는... 이걸 어떻게 처리해야 하나 고민했다
재귀함수가 익숙하지가 않아서 ㅠ_ㅠ
결국 노트를 펴서 정리해서 적어놓기 시작함.
num === 9
9 -2 -2 -2 -2 = 1
7 -2 -2 -2 = 1
5 -2 -2 = 1
3 -2 = 1
약간 반복문은 -2를 반복해서 빼주는 게 중점이라고 한다면,
재귀함수는 내가 받은 수 자체에서 하나씩 덜어내어 결론에 다다르게 하는..?
뭐랄까 설명하기가 좀 애매한데 계속 한 번 처리한 것을 묶어나가는 부분을 계속 생각하면 쉽게 풀리는 것 같다.. 근데 이것도 걍 내 머릿속에서 나온거라 설명이 애매함ㅋㅋㅋㅋ
수를 입력받아 n-factorial(n!; 엔-팩토리얼) 값을 리턴해야 합니다.
function factorial(num) {
// 1 * 2 * 3 * ... * num-1 * num
// base case = 1
if (num === 1 || num === 0) return 1
else return num * factorial(num-1)
}
팩토리얼은 예제에도 나와있던 거니까 비교적 쉽게...
수(num)를 입력받아 피보나치 수열의 num번째 요소를 리턴해야 합니다.
function fibonacci(num) {
// 피보나치 수열 = 0,1,1,2,3,5,8,13...
// num === 0 : 0
// num === 1 : 1
// (예) num = 6 -> 8 (3+5 = (num=4) + (num=5))
// num === (num-1) + (num-2) ????
if (num === 0) return 0
if (num === 1) return 1
if (num >= 2) {
return fibonacci(num-1) + fibonacci(num-2)
}
}
피보나치는 근데 약간 기계처럼 했던게, 반복문에서도 그렇고 0, 1 은 그냥 일단 세팅해야겠다라는 생각이 자리잡혀 있어서 ㅋㅋㅋㅋ 그렇게 하고 났더니 수월하게 풀렸다
배열을 입력받아 모든 요소의 합을 리턴해야 합니다.
function arrSum(arr) {
// arr[0] + arr[1] + ... + arr[n-1]
// arr[0]를 제외한 배열 -> arr.slice(1)
// arr.slice(1) = arr[0] + arr[1] + arr.slice(2)
// arr[1] + arr.slice(2) 이건 arr[0] 을 제외한 새로운 배열? 의 arr[0] + arr.slice(1) 과 같음
if(arr.length === 0) return 0
return arr[0] + arrSum(arr.slice(1))
}
이 문제는 내가 페어분한테 설명도 해줬었던 문제인데, 설명하기가 참 어려웠다.
결국에는 arr[0] 을 걷어낸 새 배열에서 또 arr[0]을 걷어낸 것이고 그것이 결국 원본 arr에서는 arr[1]이 되는 것.
이런식으로 걷어내어 더해주는 방식을 이용했다
function arrSum(arr) {
if (arr.length === 0) {
return 0;
}
// const [head, ...tail] = arr;
const head = arr[0];
const tail = arr.slice(1);
return head + arrSum(tail);
}
레퍼런스 코드인데, 레퍼런스에서는 첫번째 인자와 슬라이스한 배열을 새로 변수로 지정해주었다.
이렇게 해야하는 건강..? 🧐
(곱하기는 같으니 생략)
배열을 입력받아 그 길이를 리턴해야 합니다.
❌ 실패 코드
function arrLength(arr) {
// arr.isEmpty() === true -> 빈배열의 길이는 0
if (arr.isEmpty()) return 0
let count = 0;
if (!arr.isEmpty()) {
count++
arrLength(arr.slice(1))
} return count
}
무슨 생각으로 이렇게 했는진 모르지만, 하나씩 썰어내어 그과정에서 카운트를 하려고 했던 모양
근데 사실 이렇게 풀수도 있지 않았을까? 했는데 결국 안돼서 그냥 쓸어 엎어버렸다
function arrLength(arr) {
// arr.isEmpty() === true -> 빈배열의 길이는 0
if (arr.isEmpty()) return 0
return 1 + arrLength(arr.slice(1))
}
// arr = [5,6,7,8]
// 1 + arrLength([6,7,8])
// 1 + 1 + arrLength([7,8])
// 1 + 1 + 1 + arrLength([8])
// 1 + 1 + 1 + 1 + arrLength([])
// 1 + 1 + 1 + 1 + 0
// 답은 4
수도코드 쓰는 거 자체가 별로 습관이 안되어있어서,
그냥 일단 코드쳐보고 확인해보는 게 익숙했는데 재귀함수는 손으로 직접 써봐야 이해가 된다
아직은 많이 부족한지.. 그래도 수도코드를 쓰는 게 좋다고는 하니 열심히 쓰는 중!
수(num)와 배열을 입력받아 차례대로 num개의 요소가 제거된 새로운 배열을 리턴해야 합니다.
function drop(num, arr) {
// arr에서 num개의 요소가 제거된 새로운 배열
// num = 2 , arr = [1,2,3,4]. -> [3,4]
if (num >= arr.length) return []
if (num === 0) return arr
arr.shift() // 앞에 거 하나 제거해줌
return drop(num-1, arr) // 제거된 나머지 arr, 하나 제거했으므로 num에서 1 빼줌
}
내가 쓴 답.
약간 헤맸다.. 위에서 계속 slice를 사용했기때문에.. shift도 생각해!
function drop(num, arr) {
// if (num >= arr.length) {
// return [];
// }
if (num === 0 || arr.length === 0) {
return arr;
}
// const [head, ...tail] = arr;
const tail = arr.slice(1);
return drop(num - 1, tail);
}
근데 레퍼런스 코드에는 위에 내가 했던 부분이 주석처리가 되어있었다
그 부분이 num === 0 과, 배열의 길이가 0이거나 할 때를 arr로 출력하도록 되어있었음
저 부분을 처리하지 않아도 되는 거였을까?
if (num >= arr.length) {
return []; // num이 arr.length보다 같거나 크면 이미 arr은 []이기 때문에 return arr과 같다.
// 위에 arr.length === 0 조건이 num >= arr.length와 같은 의미
}
if (num === 0) {
return arr; // 입력된 arr 그대로 리턴
if (num >= arr.length) {
return arr;
}
if (num === 0) {
return arr;
}
if(arr.length === 0) { // arr.length === 0 과 num >= arr.length는 arr이 []일 경우를 표현하는 같은 조건
return arr;
}
if(num === 0) {
return arr;
}
if(arr.length === 0 || num === 0) {
return arr;
}
❌ 실패 코드
function take(num, arr) {
// arr에서 num개의 요소만 포함된 새로운 배열
// num = 2 , arr = [1,2,3,4] -> [1,2]
if (num >= arr.length) return arr
if (num === 0) return []
arr.pop()
return take(num-1, arr)
}
이 문제는 오히려 방금 shift를 하고 와서 slice를 잊은 케이스 ^^...
머리를 다양하게 굴려보렴..!
아무튼 pop pop 의 굴레에 빠져서 이게 왜 안되는가에 허우적 대고 있음.
사실 아직도 모르겠다.. 스터디에 물어봐야겠둠..
❌ 실패 코드 2
function take(num, arr) {
// arr에서 num개의 요소만 *순차적으로* 포함된 새로운 배열
// num = 2 , arr = [1,2,3,4] -> [1,2]
if (num >= arr.length) return arr
if (num === 0) return []
let arr2 = arr[0]
return arr2.push(take(num-1, arr.slice(1)))
}
이건 좀 부끄러운 ... 코드인데 왜냐면 출력값이 배열인지 문자열인지 아주 바보바보같이 헷갈려했던 문제
arr[0]이면 문자열로 출력되며, 이것을 arr[0]으로 해봤자 문자열 하나가 변수에 지정되었을 뿐임
그러니 문자열 하나에 백날 push 해봤자 배열이 아니니 추가가 될리가 만무함
게다가 push 는 새로운 배열을 반환하므로 문제(immutability)에 적합하지가 않다..
function take(num, arr) {
// arr에서 num개의 요소만 *순차적으로* 포함된 새로운 배열
// num = 2 , arr = [1,2,3,4] -> [1,2]
if (num >= arr.length) return arr
if (num === 0) return []
return [arr[0]].concat(take(num-1, arr.slice(1)))
}
드디어 성공했다 ㅠㅠ .concat을 사용했음
레퍼런스는 arr[0]과 arr.slice(1)을 변수로 지정해주었고.. 나는 일단 냅다 적음
더 지저분한 거 같기도 하고.. ㅠㅠ
아무튼 성공했다.
배열을 입력받아 모든 요소의 논리곱(and)을 리턴해야 합니다.
function and(arr) {
// false 인 경우 = 하나라도 false이면..
if (arr.length === 0) return true
return arr[0] && and(arr.slice(1))
}
약간 문제 이해하는데에는 힘들었으나 뭔가 깨달음을 얻고 난뒤엔 허무하리 만큼 쉬웠다..ㅋ_ㅋ
배열을 입력받아 모든 요소의 논리합(or)을 리턴해야 합니다.
function or(arr) {
// 하나라도 true 이면 true
// 전부 false 여야지만 false
if (!arr.length) return false
return arr[0] || or(arr.slice(1))
}
앞에 문제랑 비슷한듯 싶지만 이거 비밀인데 나는 조금 헤맸다.. ㅋㅋ
왜냐하면.. 전부 false 여야지 false로 출력하는 걸로 풀었는데
답이 안나오더라 ㅠㅠ 그래서 일단 페어분이 푸신 대로 ||로 풀었음
배열을 입력받아 순서가 뒤집힌 배열을 리턴해야 합니다.
function reverseArr(arr) {
if (arr.length === 0) return []
return reverseArr(arr.slice(1)).concat(arr[0])
}
마찬가지로 concat을 이용해서 배열로 만들어줌.
앞에서는 계속 더하기.. 라든지 사칙연산을 이요한 문제여서 그냥 더해줬는데
이렇게 배열로 출력하라고 할때는 concat을 이용하기..!
그리고 slice(-1)로 해서 시간초과가 나왔다.. ㅎ_ㅎ 왜 -1을 했을까 마지막 걸 빼는게 아닌데!
원본 배열의 첫번째요소를 마지막에 넣어야했던 것 뿐.. 차근차근..
머리로는 이해가 되는데 이걸 구현해 내는 과정에서 혼동이 있었나보다
러시아 전통인형 마트료시카에 대한 정보를 담은 객체와 수를 입력받아 조건에 맞는 인형이 있는지 여부를 리턴해야 합니다.
function findMatryoshka(matryoshka, size) {
// matryoshka.size === size -> true ???
// 처음 마트료시카 인형의 사이즈와 입력받은 사이즈가 다르면, (인형의 사이즈가 더 커야함)
// find마트료~함수를 다시 돌려준다. (인자는 mat~.mat~) ??
// 아.. 그리고 mat.mat가 존재해야 하나? (-> matryoshka: null이면 안됨)
if(matryoshka.size === size) return true
else if(matryoshka.size > size && matryoshka.matryoshka)
return findMatryoshka(matryoshka.matryoshka, size)
else return false
}
어찌 어찌 풀었다.. 마트료시카
선물 상자에 대한 정보를 담은 배열과 문자열을 입력받아 조건에 맞는 선물이 있는지 여부를 리턴해야 합니다.
❌ 실패 코드 (잘 모르겠음..)
function unpackGiftbox(giftBox, wish) {
// giftBox에 wish가 있는지 확인 -> 있으면 true
// 만약 giftBox속에 또 giftBox박스가 있다면~ 거기서도 확인해 -> true
// 그런데도 없으면 false???
if (giftBox.length===0 || wish.length === 0) return false
else if (giftBox.indexOf(wish)) return true
else if (giftBox) .. ????????????????? ^^
}
약간 도저히 머리가 돌아가질 않아서.. ㅠ_ㅠ 레퍼런스를 보고 공부해보기로 했다
function unpackGiftbox(giftBox, wish) {
// recursive case
for (let i = 0; i < giftBox.length; i++) { // giftbox 배열을 돌면서,
if (giftBox[i] === wish) { // 일단 겉 배열에서 비교해서 true 출력
return true;
} else if (Array.isArray(giftBox[i])) { // 만약 giftBox의 한 index가 배열일 경우에는,
const result = unpackGiftbox(giftBox[i], wish); // 재귀함수를 이용하여 그 배열 자체를 새로운 배열 인자로 넣어준다
if (result === true) { // 그래서 결과가 true 값이 나오면
return true; // 최종 결과로 true 출력
}
}
}
// base case
return false;
}
function unpackGiftbox(giftBox, wish) {
// recursive case
let anotherBoxes = []; // 또 다른 빈 배열 하나를 선언해준다
for (let i = 0; i < giftBox.length; i++) {
if (giftBox[i] === wish) {
return true; // giftbox의 한 원소가 wish 일 경우 true,
} else if (Array.isArray(giftBox[i])) { // giftBox의 원소가 배열일 경우...
anotherBoxes = anotherBoxes.concat(giftBox[i]);
} // 아까 선언해놨던 배열에 그 원소를 추가한다.
}
if (anotherBoxes.length > 0) { // 그 배열이 존재하게 된다면...?
return unpackGiftbox(anotherBoxes, wish); // 그 배열을 가지고 재귀함수를 돌려준다.
}
// base case
return false;
}
function unpackGiftbox(giftBox, wish) {
const result = giftBox.reduce((acc, curr) => {
if (curr === wish) {
return true;
} else if (Array.isArray(curr)) {
return unpackGiftbox(curr, wish) || acc;
} else {
return acc;
}
}, false);
return result;
}
** 이해가 필요..
다차원 배열을 입력받아 1차원 배열로 변환하여 리턴해야 합니다.
function flattenArr(arr) {
// base case
if (arr.length === 0) {
return [];
}
// recursive case
const head = arr[0];
const tail = arr.slice(1);
if (Array.isArray(head)) {
return flattenArr([...head, ...tail]);
} else {
return [head].concat(flattenArr(tail));
}
}
function flattenArr(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
const flattend = flattenArr(arr[i]);
result.push(...flattend);
} else {
result.push(arr[i]);
}
}
return result;
}
function flattenArr(arr) {
return arr.reduce(function (result, item) {
if (Array.isArray(item)) {
const flattened = flattenArr(item);
return [...result, ...flattened];
} else {
return [...result, item];
}
}, []);
}
블로깅에 정성이.. 가득가득하네요 저도 본받겠습니다 ^^