javascript
exercises
exercises.js⚡javascript
/**
* =====================================================
* 5.8 RECURSION - EXERCISES
* =====================================================
* Practice recursive problem solving
*/
/**
* Exercise 1: Countdown
*
* Write a recursive function that counts down from n to 1,
* then prints "Blastoff!"
*/
console.log('Exercise 1: Countdown');
function countdown(n) {
// TODO: Implement recursive countdown
}
// Test:
// countdown(5);
// Should print: 5 4 3 2 1 Blastoff!
/**
* Exercise 2: Sum to N
*
* Calculate the sum of all numbers from 1 to n.
*/
console.log('\nExercise 2: Sum to N');
function sumToN(n) {
// TODO: Implement recursively
}
// Test:
// console.log(sumToN(5)); // 15 (1+2+3+4+5)
// console.log(sumToN(10)); // 55
/**
* Exercise 3: Factorial
*
* Calculate n! (n factorial).
*/
console.log('\nExercise 3: Factorial');
function factorial(n) {
// TODO: Implement recursively
}
// Test:
// console.log(factorial(5)); // 120
// console.log(factorial(0)); // 1
/**
* Exercise 4: Fibonacci
*
* Return the nth Fibonacci number.
* Bonus: Make it efficient with memoization.
*/
console.log('\nExercise 4: Fibonacci');
function fibonacci(n) {
// TODO: Implement recursively
}
// Test:
// console.log(fibonacci(10)); // 55
// console.log(fibonacci(20)); // 6765
/**
* Exercise 5: Power
*
* Calculate base^exponent recursively.
*/
console.log('\nExercise 5: Power');
function power(base, exponent) {
// TODO: Implement recursively
// Bonus: Handle negative exponents
}
// Test:
// console.log(power(2, 10)); // 1024
// console.log(power(3, 4)); // 81
/**
* Exercise 6: Sum Array
*
* Calculate the sum of all elements in an array.
*/
console.log('\nExercise 6: Sum Array');
function sumArray(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(sumArray([1, 2, 3, 4, 5])); // 15
// console.log(sumArray([])); // 0
/**
* Exercise 7: Count Elements
*
* Count elements in an array (don't use .length in recursive calls).
*/
console.log('\nExercise 7: Count Elements');
function countElements(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(countElements([1, 2, 3, 4, 5])); // 5
// console.log(countElements([])); // 0
/**
* Exercise 8: Reverse String
*
* Reverse a string recursively.
*/
console.log('\nExercise 8: Reverse String');
function reverseString(str) {
// TODO: Implement recursively
}
// Test:
// console.log(reverseString("hello")); // "olleh"
// console.log(reverseString("JavaScript")); // "tpircSavaJ"
/**
* Exercise 9: Palindrome Check
*
* Check if a string is a palindrome.
*/
console.log('\nExercise 9: Palindrome Check');
function isPalindrome(str) {
// TODO: Implement recursively
}
// Test:
// console.log(isPalindrome("racecar")); // true
// console.log(isPalindrome("hello")); // false
// console.log(isPalindrome("a")); // true
/**
* Exercise 10: Find Max
*
* Find the maximum value in an array.
*/
console.log('\nExercise 10: Find Max');
function findMax(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(findMax([3, 1, 4, 1, 5, 9, 2, 6])); // 9
// console.log(findMax([1])); // 1
// =====================================================
// INTERMEDIATE EXERCISES
// =====================================================
/**
* Exercise 11: Flatten Array
*
* Flatten a nested array to a single level.
*/
console.log('\nExercise 11: Flatten Array');
function flatten(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(flatten([1, [2, [3, [4]]]])); // [1, 2, 3, 4]
// console.log(flatten([[1, 2], [3, [4, 5]]])); // [1, 2, 3, 4, 5]
/**
* Exercise 12: Deep Clone
*
* Create a deep copy of an object.
*/
console.log('\nExercise 12: Deep Clone');
function deepClone(obj) {
// TODO: Implement recursively
}
// Test:
// const original = { a: 1, b: { c: 2 } };
// const cloned = deepClone(original);
// console.log(cloned); // { a: 1, b: { c: 2 } }
// console.log(cloned === original); // false
// console.log(cloned.b === original.b); // false
/**
* Exercise 13: Binary Search
*
* Find index of target in sorted array, or -1 if not found.
*/
console.log('\nExercise 13: Binary Search');
function binarySearch(arr, target, left = 0, right = arr.length - 1) {
// TODO: Implement recursively
}
// Test:
// const sorted = [1, 3, 5, 7, 9, 11, 13];
// console.log(binarySearch(sorted, 7)); // 3
// console.log(binarySearch(sorted, 8)); // -1
/**
* Exercise 14: Count Nested Value
*
* Count occurrences of a value in nested arrays.
*/
console.log('\nExercise 14: Count Nested Value');
function countNested(arr, target) {
// TODO: Implement recursively
}
// Test:
// console.log(countNested([1, [1, 2, [1, 3]], 1], 1)); // 4
// console.log(countNested([1, [2, [3]]], 5)); // 0
/**
* Exercise 15: Get All Keys
*
* Get all keys from a nested object.
*/
console.log('\nExercise 15: Get All Keys');
function getAllKeys(obj) {
// TODO: Implement recursively
}
// Test:
// const nested = { a: 1, b: { c: 2, d: { e: 3 } } };
// console.log(getAllKeys(nested)); // ["a", "b", "c", "d", "e"]
// =====================================================
// ADVANCED EXERCISES
// =====================================================
/**
* Bonus 1: Generate Subsets
*
* Generate all subsets (power set) of an array.
*/
console.log('\nBonus 1: Generate Subsets');
function subsets(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(subsets([1, 2, 3]));
// [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
/**
* Bonus 2: Merge Sort
*
* Implement merge sort recursively.
*/
console.log('\nBonus 2: Merge Sort');
function mergeSort(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(mergeSort([3, 1, 4, 1, 5, 9, 2, 6]));
// [1, 1, 2, 3, 4, 5, 6, 9]
/**
* Bonus 3: Parse Nested JSON Path
*
* Get value from object using path string like "a.b.c".
*/
console.log('\nBonus 3: Parse Nested Path');
function getPath(obj, path) {
// TODO: Implement recursively
}
// Test:
// const data = { a: { b: { c: 42 } } };
// console.log(getPath(data, "a.b.c")); // 42
// console.log(getPath(data, "a.b")); // { c: 42 }
/**
* Bonus 4: GCD of Array
*
* Find greatest common divisor of all numbers in array.
*/
console.log('\nBonus 4: GCD of Array');
function gcdArray(arr) {
// TODO: Implement recursively
}
// Test:
// console.log(gcdArray([12, 18, 24])); // 6
// console.log(gcdArray([5, 10, 15])); // 5
/**
* Bonus 5: Tree Traversal
*
* Collect all values from a tree structure.
*/
console.log('\nBonus 5: Tree Traversal');
function collectValues(node) {
// TODO: Implement recursively
}
// Test:
// const tree = {
// value: 1,
// children: [
// { value: 2, children: [] },
// { value: 3, children: [
// { value: 4, children: [] }
// ]}
// ]
// };
// console.log(collectValues(tree)); // [1, 2, 3, 4]
// =====================================================
// SOLUTIONS (Uncomment to check your answers)
// =====================================================
/*
// Exercise 1 Solution:
function countdown(n) {
if (n <= 0) {
console.log("Blastoff!");
return;
}
console.log(n);
countdown(n - 1);
}
// Exercise 2 Solution:
function sumToN(n) {
if (n <= 0) return 0;
return n + sumToN(n - 1);
}
// Exercise 3 Solution:
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// Exercise 4 Solution (with memoization):
function fibonacci(n, memo = {}) {
if (n in memo) return memo[n];
if (n <= 1) return n;
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
return memo[n];
}
// Exercise 5 Solution:
function power(base, exponent) {
if (exponent === 0) return 1;
if (exponent < 0) return 1 / power(base, -exponent);
return base * power(base, exponent - 1);
}
// Exercise 6 Solution:
function sumArray(arr, index = 0) {
if (index >= arr.length) return 0;
return arr[index] + sumArray(arr, index + 1);
}
// Exercise 7 Solution:
function countElements(arr) {
if (arr.length === 0) return 0;
return 1 + countElements(arr.slice(1));
}
// Exercise 8 Solution:
function reverseString(str) {
if (str.length <= 1) return str;
return reverseString(str.slice(1)) + str[0];
}
// Exercise 9 Solution:
function isPalindrome(str) {
if (str.length <= 1) return true;
if (str[0] !== str[str.length - 1]) return false;
return isPalindrome(str.slice(1, -1));
}
// Exercise 10 Solution:
function findMax(arr, index = 0, max = -Infinity) {
if (index >= arr.length) return max;
return findMax(arr, index + 1, arr[index] > max ? arr[index] : max);
}
// Exercise 11 Solution:
function flatten(arr) {
let result = [];
for (const item of arr) {
if (Array.isArray(item)) {
result = result.concat(flatten(item));
} else {
result.push(item);
}
}
return result;
}
// Exercise 12 Solution:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) return obj.map(item => deepClone(item));
const clone = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}
// Exercise 13 Solution:
function binarySearch(arr, target, left = 0, right = arr.length - 1) {
if (left > right) return -1;
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] > target) return binarySearch(arr, target, left, mid - 1);
return binarySearch(arr, target, mid + 1, right);
}
// Exercise 14 Solution:
function countNested(arr, target) {
let count = 0;
for (const item of arr) {
if (Array.isArray(item)) {
count += countNested(item, target);
} else if (item === target) {
count++;
}
}
return count;
}
// Exercise 15 Solution:
function getAllKeys(obj) {
let keys = [];
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
if (typeof obj[key] === 'object' && obj[key] !== null) {
keys = keys.concat(getAllKeys(obj[key]));
}
}
}
return keys;
}
// Bonus 1 Solution:
function subsets(arr) {
if (arr.length === 0) return [[]];
const first = arr[0];
const rest = subsets(arr.slice(1));
const withFirst = rest.map(subset => [first, ...subset]);
return [...rest, ...withFirst];
}
// Bonus 2 Solution:
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i)).concat(right.slice(j));
}
// Bonus 3 Solution:
function getPath(obj, path) {
const parts = path.split('.');
if (parts.length === 1) return obj[parts[0]];
return getPath(obj[parts[0]], parts.slice(1).join('.'));
}
// Bonus 4 Solution:
function gcdArray(arr) {
if (arr.length === 1) return arr[0];
function gcd(a, b) {
if (b === 0) return a;
return gcd(b, a % b);
}
return gcd(arr[0], gcdArray(arr.slice(1)));
}
// Bonus 5 Solution:
function collectValues(node) {
if (!node) return [];
let values = [node.value];
if (node.children) {
for (const child of node.children) {
values = values.concat(collectValues(child));
}
}
return values;
}
*/