diff --git a/.eslintrc.js b/.eslintrc.js index 0779cdb..d4628e0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,25 +4,24 @@ module.exports = { node: true, jest: true, }, - extends: 'airbnb-base', + extends: "airbnb-base", overrides: [ { env: { node: true, }, - files: [ - '.eslintrc.{js,cjs}', - ], + files: [".eslintrc.{js,cjs}"], parserOptions: { - sourceType: 'script', + sourceType: "script", }, }, ], parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', + ecmaVersion: "latest", + sourceType: "module", }, rules: { - 'operator-assignment': 'off', + "operator-assignment": "off", + quotes: "off", }, }; diff --git a/problem-1/problem-1.test.js b/problem-1/problem-1.test.js index c775a02..c33c69b 100644 --- a/problem-1/problem-1.test.js +++ b/problem-1/problem-1.test.js @@ -1,18 +1,49 @@ +// 베이스 케이스를 찾는다. +// 베이스 케이스 이전의 단계를 찾는다. +// 베이스 케이스 이전의 이전 단계를 찾는다. +// 거꾸로 문제를 해결한다. + const solution = (numbers) => { + if (!numbers.length) return 0; + // 1. 가장 익숙한 방법으로 문제를 해결해 주세요. + const solution1 = numbers.reduce((prev, cur) => prev + cur, 0); + return solution1; + + // 2. 이번에는 재귀 함수로 문제를 해결해 주세요. + const solution2 = (arr, idx = 0) => { + if (idx >= arr.length) return 0; + return arr[idx] + solution2(arr, idx + 1); + }; + return solution2(numbers); + + // 3. 꼬리 재귀 함수로 바꿔보세요. + // 4. 꼬리 재귀 최적화를 통해서 최적화해 보세요. + const solution3 = () => { + let sum = 0; + let arr = [...numbers]; + while (true) { + if (!arr.length) return sum; + const first = arr[0]; + sum += first; + arr = arr.slice(1); + } + }; + return solution3(numbers); }; -test('빈 배열은 0을 반환한다', () => { +test("빈 배열은 0을 반환한다", () => { expect(solution([])).toBe(0); }); -test('배열의 합을 반환한다', () => { +test("배열의 합을 반환한다", () => { expect(solution([1, 2, 3, 4])).toBe(10); expect(solution([-1, 3, 8, 9, 10, 11])).toBe(40); }); -test('큰 배열이 입력으로 주어져도 RangeError를 던지지 않는다', () => { +test("큰 배열이 입력으로 주어져도 RangeError를 던지지 않는다,", () => { const input = Array.from({ length: 10000 }, (_, i) => i + 1); - expect(() => solution(input)) - .not.toThrowError(new RangeError('Maximum call stack size exceeded')); + expect(() => solution(input)).not.toThrowError( + new RangeError("Maximum call stack size exceeded"), + ); }); diff --git a/problem-2/problem-2.test.js b/problem-2/problem-2.test.js index 458a6b8..3986d3f 100644 --- a/problem-2/problem-2.test.js +++ b/problem-2/problem-2.test.js @@ -1,16 +1,40 @@ const solution = (n) => { + if (n <= 0) return 0; + if (n === 1) return 1; + // 1. 가장 익숙한 방법으로 문제를 해결해 주세요. + // 2. 이번에는 재귀 함수로 문제를 해결해 주세요. + return solution(n - 2) + solution(n - 1); + + // 4. 꼬리 재귀 최적화를 통해서 최적화해 보세요. + let current = 2; + let a = 0; + let b = 1; + while (true) { + if (n === current) return a + b; + current += 1; + const temp = a; + a = b; + b = temp + b; + } +}; +// 3. 꼬리 재귀 함수로 바꿔보세요. +const solution = (n, current = 2, a = 0, b = 1) => { + if (n <= 0) return 0; + if (n === 1) return 1; + if (n === current) return a + b; + return solution(n, current + 1, b, a + b); }; -test('음수가 주어지면 0을 반환한다', () => { +test("음수가 주어지면 0을 반환한다", () => { expect(solution(-1)).toBe(0); }); -test('0부터 1까지는 정해진 수를 반환한다', () => { +test("0부터 1까지는 정해진 수를 반환한다", () => { expect(solution(0)).toBe(0); expect(solution(1)).toBe(1); }); -test('2이상 주어지면 앞 두 항의 합을 반환한다', () => { +test("2이상 주어지면 앞 두 항의 합을 반환한다", () => { expect(solution(2)).toBe(1); expect(solution(3)).toBe(2); expect(solution(4)).toBe(3); @@ -18,9 +42,10 @@ test('2이상 주어지면 앞 두 항의 합을 반환한다', () => { expect(solution(6)).toBe(8); }); -test('큰 입력이 주어져도 RangeError를 던지지 않는다', () => { +test("큰 입력이 주어져도 RangeError를 던지지 않는다", () => { const input = 100000; - expect(() => solution(input)) - .not.toThrowError(new RangeError('Maximum call stack size exceeded')); + expect(() => solution(input)).not.toThrowError( + new RangeError("Maximum call stack size exceeded"), + ); }); diff --git a/problem-3/problem-3.test.js b/problem-3/problem-3.test.js index 7319eb8..79b3ff7 100644 --- a/problem-3/problem-3.test.js +++ b/problem-3/problem-3.test.js @@ -1,21 +1,30 @@ const solution = (n) => { + // 1. 가장 익숙한 방법으로 문제를 해결해 주세요. + // const solution1 = n.toString(2); + // return solution1; + // 2. 이번에는 재귀 함수로 문제를 해결해 주세요. + if (n === 0 || n === 1) return n.toString(); + const quotient = Math.floor(n / 2); + const remainder = (n % 2).toString(); + return solution(quotient) + remainder; }; -test('이진수 문자열을 반환한다', () => { - expect(solution(0)).toBe('0'); - expect(solution(1)).toBe('1'); - expect(solution(2)).toBe('10'); - expect(solution(3)).toBe('11'); - expect(solution(4)).toBe('100'); - expect(solution(5)).toBe('101'); - expect(solution(6)).toBe('110'); - expect(solution(7)).toBe('111'); - expect(solution(8)).toBe('1000'); +test("이진수 문자열을 반환한다", () => { + expect(solution(0)).toBe("0"); + expect(solution(1)).toBe("1"); + expect(solution(2)).toBe("10"); + expect(solution(3)).toBe("11"); + expect(solution(4)).toBe("100"); + expect(solution(5)).toBe("101"); + expect(solution(6)).toBe("110"); + expect(solution(7)).toBe("111"); + expect(solution(8)).toBe("1000"); }); -test('큰 입력이 주어져도 RangeError를 던지지 않는다', () => { +test("큰 입력이 주어져도 RangeError를 던지지 않는다", () => { const input = Number.MAX_VALUE; - expect(() => solution(input)) - .not.toThrowError(new RangeError('Maximum call stack size exceeded')); + expect(() => solution(input)).not.toThrowError( + new RangeError("Maximum call stack size exceeded"), + ); }); diff --git a/problem-4/problem-4.test.js b/problem-4/problem-4.test.js index 19f5cb0..1bcfc5b 100644 --- a/problem-4/problem-4.test.js +++ b/problem-4/problem-4.test.js @@ -1,21 +1,26 @@ -const solution = () => { +const solution = (n) => { + // 1. 가장 익숙한 방법으로 문제를 해결해 주세요. + const solution1 = parseInt(n, 2); + + return solution1; }; -test('10진수 숫자를 반환한다', () => { - expect(solution('0')).toBe(0); - expect(solution('1')).toBe(1); - expect(solution('10')).toBe(2); - expect(solution('11')).toBe(3); - expect(solution('100')).toBe(4); - expect(solution('101')).toBe(5); - expect(solution('110')).toBe(6); - expect(solution('111')).toBe(7); - expect(solution('1000')).toBe(8); +test("10진수 숫자를 반환한다", () => { + expect(solution("0")).toBe(0); + expect(solution("1")).toBe(1); + expect(solution("10")).toBe(2); + expect(solution("11")).toBe(3); + expect(solution("100")).toBe(4); + expect(solution("101")).toBe(5); + expect(solution("110")).toBe(6); + expect(solution("111")).toBe(7); + expect(solution("1000")).toBe(8); }); -test('큰 입력이 주어져도 RangeError를 던지지 않는다', () => { +test("큰 입력이 주어져도 RangeError를 던지지 않는다", () => { const input = Number.MAX_VALUE.toString(2); - expect(() => solution(input)) - .not.toThrowError(new RangeError('Maximum call stack size exceeded')); + expect(() => solution(input)).not.toThrowError( + new RangeError("Maximum call stack size exceeded"), + ); }); diff --git a/problem-5/problem-5.test.js b/problem-5/problem-5.test.js index 20a8fab..66e5198 100644 --- a/problem-5/problem-5.test.js +++ b/problem-5/problem-5.test.js @@ -1,17 +1,30 @@ -const solution = () => { +const solution = (a, b) => { + // 1. 가장 익숙한 방법으로 문제를 해결해 주세요. + // 2. 이번에는 재귀 함수로 문제를 해결해 주세요. + // 3. 꼬리 재귀 함수로 바꿔보세요. + if (a % b === 0) return b; + return solution(b, a % b); + // 4. 꼬리 재귀 최적화를 통해서 최적화해 보세요. + while (true) { + if (a % b === 0) return b; + const temp = a; + a = b; + b = temp % b; + } }; -test('최대 공약수를 반환한다', () => { +test("최대 공약수를 반환한다", () => { expect(solution(4, 12)).toBe(4); expect(solution(3, 7)).toBe(1); expect(solution(16, 72)).toBe(8); expect(solution(9, 12)).toBe(3); }); -test('큰 입력이 주어져도 RangeError를 던지지 않는다', () => { +test("큰 입력이 주어져도 RangeError를 던지지 않는다", () => { const a = Number.MAX_VALUE; const b = 1213; - expect(() => solution(a, b)) - .not.toThrowError(new RangeError('Maximum call stack size exceeded')); + expect(() => solution(a, b)).not.toThrowError( + new RangeError("Maximum call stack size exceeded"), + ); }); diff --git a/problem-6/problem-6.test.js b/problem-6/problem-6.test.js index 059e2b8..30ab152 100644 --- a/problem-6/problem-6.test.js +++ b/problem-6/problem-6.test.js @@ -1,7 +1,22 @@ +// 1. 재귀 함수로 문제를 해결해 주세요. const solution = (n) => { + if (n < 0) return 0; + if (n === 0) return 1; + return solution(n - 3) + solution(n - 2) + solution(n - 1); }; +// 2. 다이나믹 프로그래밍으로 최적화 해주세요. +const solution = (n, memo = {}) => { + if (n < 0) return 0; + if (n === 0) return 1; -test('계단에 오를 수 있는 가지 수를 반환한다', () => { + if (!memo[n]) { + memo[n] = + solution(n - 3, memo) + solution(n - 2, memo) + solution(n - 1, memo); + } + return memo[n]; +}; + +test("계단에 오를 수 있는 가지 수를 반환한다", () => { expect(solution(1)).toBe(1); expect(solution(2)).toBe(2); expect(solution(3)).toBe(4); @@ -14,6 +29,6 @@ test('계단에 오를 수 있는 가지 수를 반환한다', () => { expect(solution(10)).toBe(274); }); -test('큰 입력이 주어져도 시간안에 실행된다', async () => { +test("큰 입력이 주어져도 시간안에 실행된다", async () => { expect(solution(40)).toBe(23837527729); });