From 5fa104c33015f05a6c115d3d473027af73755069 Mon Sep 17 00:00:00 2001 From: Gabe Cziprusz Date: Thu, 12 Feb 2026 13:58:40 -0600 Subject: [PATCH] simplify 2 pointer content --- .../05-array-methods/index.md | 18 +- .../07-two-pointers/index.jsx | 9 +- .../07-two-pointers/index.md | 693 +----------------- .../07-two-pointers/solution.js | 221 ------ .../07-two-pointers/starterCode.js | 74 -- .../07-two-pointers/tests.js | 342 --------- 6 files changed, 47 insertions(+), 1310 deletions(-) delete mode 100644 src/sections/04-arrays-and-two-pointers/07-two-pointers/solution.js delete mode 100644 src/sections/04-arrays-and-two-pointers/07-two-pointers/starterCode.js delete mode 100644 src/sections/04-arrays-and-two-pointers/07-two-pointers/tests.js diff --git a/src/sections/04-arrays-and-two-pointers/05-array-methods/index.md b/src/sections/04-arrays-and-two-pointers/05-array-methods/index.md index d8defb0..2f39917 100644 --- a/src/sections/04-arrays-and-two-pointers/05-array-methods/index.md +++ b/src/sections/04-arrays-and-two-pointers/05-array-methods/index.md @@ -93,6 +93,7 @@ Alex adjusts their guitar strap, "That's because these operations are **O(n) tim - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. 🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* + --- ## Part 2: The Collaboration Coordinator - Transforming Data with map() and filter() @@ -593,19 +594,24 @@ Maya looks amazed, "So you can filter, transform, sort, and calculate all in one "Exactly! Each method returns an array, so I can immediately call the next method on the result. It's **O(n) time complexity** for each method in the chain, but the code reads like a story - filter the songs I want, transform them how I need, sort by importance, and extract exactly what I need." --- + ## ⏱️ **Alex's Festival Curation Challenge!** - - πŸ”“ Uncomment the below code section in the editor πŸ‘‰: +- πŸ”“ Uncomment the below code section in the editor πŸ‘‰: \`\`\`js // ============================== // Exercise 4: Help Alex Master Method Chaining and Advanced Array Operations // ============================== \`\`\` - - Read the requirements written as comments in the code. - - Implement the required logic. - - Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! - - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. +- Read the requirements written as comments in the code. +- Implement the required logic. +- Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! +- Click `Run Tests`and ensure that test(s) related to this specific exercise are passing + Passing test will show in green text. + + +*Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass. * + -🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* --- ## Alex's Array Mastery: From Street Musician to Data Wizard diff --git a/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.jsx b/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.jsx index ded22b1..3635a77 100644 --- a/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.jsx +++ b/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.jsx @@ -1,7 +1,4 @@ import content from './index.md?raw'; -import starterCode from './starterCode.js?raw'; -import solution from './solution.js?raw'; -import { tests } from './tests.js'; export default { id: "two-pointers", @@ -10,9 +7,5 @@ export default { previousChapterId: "implement-arraylist", nextChapterId: "info-sheet", content, - exercises: [{ - starterCode, - solution, - tests - }] + exercises: [] }; \ No newline at end of file diff --git a/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.md b/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.md index d09c0e6..43bfbf0 100644 --- a/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.md +++ b/src/sections/04-arrays-and-two-pointers/07-two-pointers/index.md @@ -1,687 +1,62 @@ -Meet Eleanor, the head librarian at the Grand Metropolitan Library. With over 50,000 books to organize, catalog, and maintain, Eleanor has discovered that the secret to efficient library management lies in a powerful technique: using two bookmarks to navigate through collections simultaneously. What she doesn't realize yet is that she's mastering one of programming's most elegant problem-solving patterns. - -## Part 1: The Great Book Pairing - Converging Pointers - -Eleanor faces her first challenge of the day: a patron wants to find two books whose publication years add up to exactly 2000. The books are arranged chronologically on a long shelf, and Eleanor needs to find this pair quickly before the library's morning rush. - -"I could check every possible combination," Eleanor muses, looking at the hundreds of books, "but that would take forever. There has to be a smarter way." - -### The Two-Bookmark Strategy - -Eleanor places one bookmark at the beginning of the shelf (oldest books) and another at the end (newest books). Her plan: move the bookmarks toward each other until she finds the perfect pair. - -```javascript -// Eleanor's chronologically sorted book collection -const bookYears = [1850, 1923, 1945, 1967, 1978, 1989, 1995, 2001, 2010, 2015]; -const targetYear = 2000; - -function findBookPairForYear(books, target) { - let leftBookmark = 0; // Start with oldest book - let rightBookmark = books.length - 1; // Start with newest book - - console.log("Eleanor begins her search..."); - - while (leftBookmark < rightBookmark) { - const leftYear = books[leftBookmark]; - const rightYear = books[rightBookmark]; - const combinedYear = leftYear + rightYear; - - console.log(`Checking: ${leftYear} + ${rightYear} = ${combinedYear}`); - - if (combinedYear === target) { - return { - leftBook: { position: leftBookmark, year: leftYear }, - rightBook: { position: rightBookmark, year: rightYear }, - message: `Perfect! Books from ${leftYear} and ${rightYear} sum to ${target}` - }; - } else if (combinedYear < target) { - // Sum too small, need a newer book on the left - leftBookmark++; - console.log("Sum too small, moving left bookmark forward..."); - } else { - // Sum too large, need an older book on the right - rightBookmark--; - console.log("Sum too large, moving right bookmark backward..."); - } - } - - return { message: "No pair found that sums to the target year" }; -} +## Two Pointers β€” Book Lengths Add Up -// Eleanor finds her book pair -const result = findBookPairForYear(bookYears, targetYear); -console.log(result.message); -``` +Maya is organizing a shelf of books sorted by **number of pages** (smallest to largest). +A student asks: -"Brilliant!" Eleanor exclaims as she finds books from 1945 and 1955 that sum to exactly 2000. "By moving my bookmarks strategically, I only had to check a few combinations instead of hundreds!" +> β€œCan you find two books whose page counts add up to exactly 500 pages?” -### Why Converging Pointers Work Like Magic +Maya could try every pair… but that would take too long. -Eleanor explains her technique to her assistant, Marcus: "The key insight is that our books are sorted by year. When the sum is too small, I know I need a newer book, so I move my left bookmark forward. When it's too large, I need an older book, so I move my right bookmark backward." +Instead, she uses **two bookmarks**: -This **converging pointers** technique transforms an **O(nΒ²)** brute force approach into an elegant **O(n)** solution, making it perfect for: -- Finding pairs with target sums in sorted arrays -- Detecting palindromes -- Reversing arrays in-place -- Partitioning arrays around pivot values +- One at the **shortest book** (`left`) +- One at the **longest book** (`right`) ---- -## ⏱️ **Eleanor's First Challenge!** - - πŸ”“ Uncomment the below code section in the editor πŸ‘‰: -```js -// ============================== -// Exercise 1: Help Eleanor Find Book Pairs -// ============================== -``` +If the total pages are: +- **Too small?** Move `left` right (choose a longer book). +- **Too big?** Move `right` left (choose a shorter book). +- **Exactly 500?** Found the pair! - - Read the requirements written as comments in the code. - - Implement the required logic. - - Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! - - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. +Because the books are sorted by length, she never wastes time rechecking combinations. -🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* --- -## Part 2: The Catalog Survey - Fast and Slow Pointers - -Later that morning, Eleanor faces two interesting challenges. First, she needs to quickly find the middle book in various reading lists without counting all the books. Second, she must efficiently remove duplicate entries from sorted book catalogs that have accumulated over time. - -"There has to be a way to solve both problems without examining every single book," Eleanor thinks. "What if I use two bookmarks moving at different speeds?" - -### The Tortoise and Hare Approach for Finding Middles - -Eleanor remembers an old fable about a tortoise and a hare racing. She decides to use two bookmarks: one that moves slowly through the catalog (tortoise) and one that moves quickly (hare). When the fast bookmark reaches the end, the slow one will be exactly at the middle! - -```javascript -// Eleanor's various reading lists of different lengths -const shortList = ["Book A", "Book B", "Book C"]; -const mediumList = ["Book 1", "Book 2", "Book 3", "Book 4", "Book 5"]; -const longList = [ - "The Great Gatsby", "To Kill a Mockingbird", "1984", "Pride and Prejudice", - "The Catcher in the Rye", "Lord of the Flies", "Jane Eyre", "Wuthering Heights", - "The Hobbit" -]; - -function findMiddleBook(bookList) { - if (bookList.length === 0) { - return { message: "Empty list has no middle!" }; - } - - let slowPointer = 0; // Tortoise: moves 1 step at a time - let fastPointer = 0; // Hare: moves 2 steps at a time - - console.log(`Finding middle of list with ${bookList.length} books...`); - - // Move pointers until fast pointer reaches or exceeds the end - while (fastPointer + 1 < bookList.length) { - slowPointer++; // Move slow pointer 1 step - fastPointer += 2; // Move fast pointer 2 steps - - console.log(` Slow at position ${slowPointer}: "${bookList[slowPointer]}"`); - console.log(` Fast at position ${fastPointer}: "${bookList[Math.min(fastPointer, bookList.length - 1)]}"`); - } - - return { - middleBook: bookList[slowPointer], - position: slowPointer, - totalBooks: bookList.length, - message: `Middle book is "${bookList[slowPointer]}" at position ${slowPointer}` - }; -} - -// Eleanor tests her technique on different sized lists -console.log("=== Eleanor's Middle-Finding Technique ==="); -[shortList, mediumList, longList].forEach((list, index) => { - console.log(`\nTesting list ${index + 1}:`); - const result = findMiddleBook(list); - console.log(result.message); -}); -``` - -"Brilliant!" Eleanor exclaims. "When the fast bookmark moves 2 steps for every 1 step of the slow bookmark, the slow one ends up exactly in the middle when the fast one reaches the end!" - -### The Duplicate Detective - Two-Pointer Cleanup - -Eleanor's second challenge involves cleaning up sorted book catalogs that have accumulated duplicate entries over time. She develops a clever technique using two pointers: one to read through the catalog, and another to write only unique books. - -```javascript -// Eleanor's sorted catalog with duplicate entries -const catalogWithDuplicates = [ - "1984", "1984", "Animal Farm", "Brave New World", "Brave New World", "Brave New World", - "Dune", "Foundation", "Foundation", "The Great Gatsby", "The Great Gatsby", "The Hobbit" -]; - -function removeDuplicatesFromSortedCatalog(sortedBooks) { - if (sortedBooks.length === 0) { - return { cleanCatalog: [], duplicatesRemoved: 0 }; - } - - console.log("Eleanor begins duplicate removal..."); - console.log("Original catalog:", sortedBooks); - - let writePointer = 0; // Points to where next unique book should go - let duplicatesRemoved = 0; - - // Start reading from the second book (index 1) - for (let readPointer = 1; readPointer < sortedBooks.length; readPointer++) { - const currentBook = sortedBooks[readPointer]; - const lastUniqueBook = sortedBooks[writePointer]; - - console.log(` Comparing "${currentBook}" with last unique "${lastUniqueBook}"`); - - if (currentBook !== lastUniqueBook) { - // Found a new unique book - move it to the write position - writePointer++; - sortedBooks[writePointer] = currentBook; - console.log(` βœ“ Keeping unique book: "${currentBook}" at position ${writePointer}`); - } else { - // Found a duplicate - skip it - duplicatesRemoved++; - console.log(` βœ— Removing duplicate: "${currentBook}"`); - } - } - - // Create clean catalog with only unique books - const cleanCatalog = sortedBooks.slice(0, writePointer + 1); - - return { - cleanCatalog: cleanCatalog, - originalCount: sortedBooks.length, - uniqueCount: cleanCatalog.length, - duplicatesRemoved: duplicatesRemoved, - message: `Removed ${duplicatesRemoved} duplicates. Clean catalog has ${cleanCatalog.length} unique books.` - }; -} - -// Eleanor cleans up her catalog -const cleanupResult = removeDuplicatesFromSortedCatalog([...catalogWithDuplicates]); -console.log("\n" + cleanupResult.message); -console.log("Clean catalog:", cleanupResult.cleanCatalog); -``` - -### Advanced Pattern: Finding Duplicates in Unsorted Arrays - -Eleanor discovers another useful application: detecting if any book appears more than once in an unsorted collection, using a clever mathematical approach with fast and slow pointers. - -```javascript -// Eleanor's unsorted collection where book IDs might repeat -// (Using numbers 1-6 to represent book IDs, with one guaranteed duplicate) -const bookIds = [3, 1, 4, 2, 5, 2, 6]; // Book ID 2 appears twice - -function findDuplicateBookId(bookIds) { - // This uses Floyd's cycle detection on the array treated as a function - // where bookIds[i] points to the next position - console.log("Eleanor searches for duplicate book ID..."); - console.log("Book IDs:", bookIds); - - let slowPointer = bookIds[0]; - let fastPointer = bookIds[0]; - - // Phase 1: Find intersection point in the "cycle" - do { - slowPointer = bookIds[slowPointer]; // Move 1 step - fastPointer = bookIds[bookIds[fastPointer]]; // Move 2 steps - console.log(` Slow pointer at ID ${slowPointer}, Fast pointer at ID ${fastPointer}`); - } while (slowPointer !== fastPointer); - - // Phase 2: Find the start of the cycle (the duplicate) - let finder = bookIds[0]; - while (finder !== slowPointer) { - finder = bookIds[finder]; - slowPointer = bookIds[slowPointer]; - } - - return { - duplicateId: finder, - message: `Found duplicate book ID: ${finder}` - }; -} - -// Eleanor finds the duplicate -const duplicateResult = findDuplicateBookId(bookIds); -console.log("\n" + duplicateResult.message); -``` - -This **fast and slow pointers** technique excels at: -- Finding middle elements without counting (**O(n)** time, **O(1)** space) -- Removing duplicates from sorted arrays (**O(n)** time, **O(1)** space) -- Detecting duplicates in special array configurations -- Partitioning arrays based on conditions +## The Code ---- -## ⏱️ **Eleanor's Detection Challenge!** - - πŸ”“ Uncomment this block and click "Run Code" to complete the exercise: ```js -// ============================== -// Exercise 2: Help Eleanor Detect Patterns -// ============================== -``` - - - Read the requirements written as comments in the code. - - Implement the required logic. - - Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! - - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. - -🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* - ---- - -## Part 3: The Catalog Window - Sliding Window Technique - -That afternoon, Eleanor faces a new challenge: the library's computer system needs to analyze reading patterns. She wants to find the most popular consecutive sequence of books in different sections, but the window of analysis keeps changing based on patron requests. - -"I need a flexible way to examine different-sized windows of our catalog," Eleanor realizes. "Something that can expand and contract as needed." - -### The Adjustable Reading Window - -Eleanor develops a technique using two bookmarks that define a "window" of books. She can slide this window across her catalog, expanding or contracting it based on what she's analyzing. - -```javascript -// Eleanor's book popularity scores for the fiction section -const fictionPopularity = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]; -const bookTitles = [ - "The Great Gatsby", "Moby Dick", "To Kill a Mockingbird", "1984", - "Pride and Prejudice", "The Catcher in the Rye", "Lord of the Flies", - "Jane Eyre", "Wuthering Heights", "The Hobbit", "Dune", - "Foundation", "Neuromancer", "Brave New World", "Fahrenheit 451" -]; +function findBooksByPageCount(pages, target) { + let left = 0; + let right = pages.length - 1; -function findMostPopularBookSequence(popularity, titles, windowSize) { - if (windowSize > popularity.length) { - return { message: "Window size larger than catalog!" }; - } - - let windowStart = 0; - let windowSum = 0; - let maxSum = 0; - let bestWindowStart = 0; - - console.log(`Eleanor analyzes sequences of ${windowSize} books...`); - - // Calculate sum of first window - for (let i = 0; i < windowSize; i++) { - windowSum += popularity[i]; - } - maxSum = windowSum; - - console.log(`First window (${windowStart} to ${windowStart + windowSize - 1}): sum = ${windowSum}`); - - // Slide the window across the catalog - for (let windowEnd = windowSize; windowEnd < popularity.length; windowEnd++) { - // Slide window: remove leftmost element, add rightmost element - windowSum = windowSum - popularity[windowStart] + popularity[windowEnd]; - windowStart++; - - console.log(`Window (${windowStart} to ${windowEnd}): sum = ${windowSum}`); - - // Update maximum if current window is better - if (windowSum > maxSum) { - maxSum = windowSum; - bestWindowStart = windowStart; - } - } - - // Get the titles of the most popular sequence - const bestSequence = titles.slice(bestWindowStart, bestWindowStart + windowSize); - - return { - maxPopularity: maxSum, - startPosition: bestWindowStart, - books: bestSequence, - message: `Most popular sequence of ${windowSize} books has total popularity ${maxSum}` - }; -} -``` + while (left < right) { + const sum = pages[left] + pages[right]; -### Dynamic Window for Variable Requirements + if (sum === target) return [left, right]; + if (sum < target) left++; // need more pages + else right--; // need fewer pages + } -Eleanor's technique becomes even more powerful when she needs to find sequences that meet changing criteria, like finding the shortest sequence of books with a total popularity above a certain threshold. - -```javascript -function findShortestSequenceAboveThreshold(popularity, titles, threshold) { - let windowStart = 0; - let windowSum = 0; - let minLength = Infinity; - let bestStart = 0; - let bestLength = 0; - - console.log(`Finding shortest sequence with popularity > ${threshold}...`); - - for (let windowEnd = 0; windowEnd < popularity.length; windowEnd++) { - // Expand window by including current book - windowSum += popularity[windowEnd]; - - // Contract window while sum is still above threshold - while (windowSum >= threshold && windowStart <= windowEnd) { - const currentLength = windowEnd - windowStart + 1; - console.log(`Window [${windowStart}, ${windowEnd}]: sum = ${windowSum}, length = ${currentLength}`); - - if (currentLength < minLength) { - minLength = currentLength; - bestStart = windowStart; - bestLength = currentLength; - } - - // Try to shrink window from left - windowSum -= popularity[windowStart]; - windowStart++; - } - } - - if (minLength === Infinity) { - return { message: `No sequence found with popularity above ${threshold}` }; - } - - const bestSequence = titles.slice(bestStart, bestStart + bestLength); - - return { - minLength: minLength, - startPosition: bestStart, - books: bestSequence, - totalPopularity: popularity.slice(bestStart, bestStart + bestLength).reduce((a, b) => a + b, 0), - message: `Shortest sequence above threshold: ${minLength} books` - }; + return null; } -``` -The **sliding window** technique transforms **O(nΒ²)** nested loops into **O(n)** solutions for: -- Finding maximum/minimum sum subarrays of fixed size -- Longest substring problems with constraints -- Finding shortest subarrays meeting criteria -- Analyzing patterns in sequential data +// Example (sorted page counts) +const bookPages = [120, 150, 180, 200, 220, 250, 300]; ---- -## ⏱️ **Eleanor's Window Challenge!** - - πŸ”“ Uncomment this block and click "Run Code" to complete the exercise: -```js -// ============================== -// Exercise 3: Help Eleanor Analyze Book Sequences -// ============================== +console.log(findBooksByPageCount(bookPages, 500)); +// 200 + 300 = 500 β†’ returns [3, 6] ``` - - Read the requirements written as comments in the code. - - Implement the required logic. - - Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! - - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. - -🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* - ---- - -## Part 4: The Palindrome Mystery - Symmetry Detection - -As evening approaches, Eleanor discovers an intriguing mystery: several book titles in the rare books section seem to read the same forwards and backwards. A patron is curious about palindromic titles, and Eleanor needs to verify which ones are true palindromes. - -"A palindrome should read identically from both directions," Eleanor muses. "I can use my two-bookmark technique to check this efficiently!" - -### The Mirror Reading Technique - -Eleanor places one bookmark at the beginning of a title and another at the end, then moves them toward each other, comparing characters as she goes. - -```javascript -// Eleanor's collection of potentially palindromic book titles -const mysteriousTitles = [ - "A Santa at NASA", - "Madam", - "Was it a car or a cat I saw", - "The Great Gatsby", - "A man a plan a canal Panama", - "Racecar", - "Hello World", - "Never odd or even" -]; - -function checkIfPalindrome(title) { - // Clean the title: remove spaces and convert to lowercase - const cleanTitle = title.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); - - let leftBookmark = 0; - let rightBookmark = cleanTitle.length - 1; - - console.log(`Checking "${title}" (cleaned: "${cleanTitle}")`); - - while (leftBookmark < rightBookmark) { - const leftChar = cleanTitle[leftBookmark]; - const rightChar = cleanTitle[rightBookmark]; - - console.log(` Comparing '${leftChar}' at position ${leftBookmark} with '${rightChar}' at position ${rightBookmark}`); - - if (leftChar !== rightChar) { - return { - isPalindrome: false, - title: title, - message: `"${title}" is NOT a palindrome - '${leftChar}' β‰  '${rightChar}'` - }; - } - - leftBookmark++; - rightBookmark--; - } - - return { - isPalindrome: true, - title: title, - message: `"${title}" IS a palindrome! βœ“` - }; -} - -// Eleanor checks each mysterious title -console.log("Eleanor's Palindrome Investigation:"); -console.log("====================================="); - -const palindromeResults = mysteriousTitles.map(title => { - const result = checkIfPalindrome(title); - console.log(result.message); - return result; -}); - -// Summary of findings -const truePalindromes = palindromeResults.filter(result => result.isPalindrome); -console.log(`\nEleanor found ${truePalindromes.length} true palindromes!`); -truePalindromes.forEach(p => console.log(` - ${p.title}`)); -``` - -"Fascinating!" Eleanor exclaims. "By moving my bookmarks from both ends toward the center, I can verify palindromes in **O(n)** time - much more efficient than reversing the entire string and comparing!" - ---- -## ⏱️ **Eleanor's Palindrome Challenge!** - - πŸ”“ Uncomment this block and click "Run Code" to complete the exercise: -```js -// ============================== -// Exercise 4: Help Eleanor Solve Palindrome Mysteries -// ============================== -``` - - - Read the requirements written as comments in the code. - - Implement the required logic. - - Click `Run Code` and inspect `πŸ“‹ Console Output` window for correctness! - - Click `Run Tests`and ensure that test(s) related to this specific exercise are passing Passing test will show in green text. - -🚧 *Some tests for future exercises may fail at first β€” that’s expected. As you complete each exercise, those tests will start passing. By the time you finish the final exercise, all tests in the test suite should pass.* - ---- - -## Part 5: The Grand Reorganization - Advanced Applications - -As the library prepares to close, Eleanor faces her biggest challenge yet: reorganizing the entire fiction section. Books need to be sorted, duplicates removed, and special collections merged. Her two-pointer mastery will be put to the ultimate test. - -### Merging Two Sorted Collections - -Eleanor needs to merge two pre-sorted book collections into one master list while maintaining alphabetical order. - -```javascript -// Eleanor's two sorted collections to merge -const classicLiterature = [ - "Animal Farm", "Brave New World", "Great Expectations", - "Jane Eyre", "Pride and Prejudice" -]; - -const modernFiction = [ - "Dune", "Foundation", "Neuromancer", - "The Handmaid's Tale", "The Road" -]; - -function mergeSortedCollections(collection1, collection2) { - const mergedCollection = []; - let pointer1 = 0; // Pointer for first collection - let pointer2 = 0; // Pointer for second collection - - console.log("Eleanor begins merging two sorted collections..."); - - // Compare and merge while both collections have books remaining - while (pointer1 < collection1.length && pointer2 < collection2.length) { - const book1 = collection1[pointer1]; - const book2 = collection2[pointer2]; - - console.log(`Comparing "${book1}" vs "${book2}"`); - - if (book1.localeCompare(book2) <= 0) { - mergedCollection.push(book1); - console.log(` Added "${book1}" from classics`); - pointer1++; - } else { - mergedCollection.push(book2); - console.log(` Added "${book2}" from modern fiction`); - pointer2++; - } - } - - // Add remaining books from whichever collection isn't finished - while (pointer1 < collection1.length) { - mergedCollection.push(collection1[pointer1]); - console.log(` Added remaining classic: "${collection1[pointer1]}"`); - pointer1++; - } - - while (pointer2 < collection2.length) { - mergedCollection.push(collection2[pointer2]); - console.log(` Added remaining modern: "${collection2[pointer2]}"`); - pointer2++; - } - - return { - mergedBooks: mergedCollection, - totalBooks: mergedCollection.length, - message: `Successfully merged ${collection1.length + collection2.length} books in alphabetical order` - }; -} - -// Eleanor merges her collections -const mergeResult = mergeSortedCollections(classicLiterature, modernFiction); -console.log(mergeResult.message); -console.log("Final merged collection:", mergeResult.mergedBooks); -``` - -### Removing Duplicates from Sorted Collection - -Eleanor discovers some books appear multiple times in her sorted collection and needs to remove duplicates efficiently. - -```javascript -function removeDuplicatesFromSortedCollection(sortedBooks) { - if (sortedBooks.length === 0) return { books: [], removed: 0 }; - - let writePointer = 0; // Points to position for next unique book - let duplicatesRemoved = 0; - - console.log("Eleanor removes duplicates from sorted collection..."); - console.log("Original collection:", sortedBooks); - - // Read pointer starts from second book - for (let readPointer = 1; readPointer < sortedBooks.length; readPointer++) { - const currentBook = sortedBooks[readPointer]; - const lastUniqueBook = sortedBooks[writePointer]; - - if (currentBook !== lastUniqueBook) { - // Found a new unique book - writePointer++; - sortedBooks[writePointer] = currentBook; - console.log(` Keeping unique book: "${currentBook}"`); - } else { - // Found a duplicate - duplicatesRemoved++; - console.log(` Removing duplicate: "${currentBook}"`); - } - } - - // Trim the array to remove the duplicates at the end - const uniqueBooks = sortedBooks.slice(0, writePointer + 1); - - return { - books: uniqueBooks, - originalCount: sortedBooks.length, - uniqueCount: uniqueBooks.length, - removed: duplicatesRemoved, - message: `Removed ${duplicatesRemoved} duplicates, ${uniqueBooks.length} unique books remain` - }; -} - -// Eleanor's collection with duplicates -const booksWithDuplicates = [ - "1984", "1984", "Animal Farm", "Brave New World", "Brave New World", - "Dune", "Dune", "Foundation", "The Hobbit", "The Hobbit", "The Hobbit" -]; - -const deduplicationResult = removeDuplicatesFromSortedCollection([...booksWithDuplicates]); -console.log(deduplicationResult.message); -console.log("Unique collection:", deduplicationResult.books); -``` - -## Eleanor's Library Mastery: The Three Pillars of Two-Pointer Technique - -As Eleanor locks up the library for the night, she reflects on how her bookmark techniques have revolutionized her approach to organizing information. She's discovered the three fundamental patterns that make two-pointer techniques so powerful. - -### 🎯 **The Three Pillars of Two-Pointer Mastery** - -#### 1. **Converging Pointers** - The Meeting in the Middle (O(n)) -"When I need to find relationships between elements at opposite ends." -```javascript -// Perfect for: pair finding, palindromes, array reversal -let left = 0, right = array.length - 1; -while (left < right) { - // Process and move pointers toward each other - left++; right--; -} -``` - -#### 2. **Fast and Slow Pointers** - The Tortoise and Hare (O(n)) -"When I need to detect patterns or find middle elements without extra space." -```javascript -// Perfect for: cycle detection, finding middle, removing duplicates -let slow = 0, fast = 0; -while (fast < array.length) { - slow++; fast += 2; // Or move based on problem requirements -} -``` - -#### 3. **Sliding Window** - The Adjustable Frame (O(n)) -"When I need to analyze consecutive sequences with changing requirements." -```javascript -// Perfect for: subarray problems, substring analysis, optimization -let windowStart = 0; -for (let windowEnd = 0; windowEnd < array.length; windowEnd++) { - // Expand window, then contract as needed - while (/* condition met */) windowStart++; -} -``` - -### πŸ›οΈ **Eleanor's Library Philosophy** - -"Tonight taught me that managing a library is just like solving algorithmic problems," Eleanor muses while organizing her notes. "The key insights are:" - -1. **Recognize the Pattern**: Is this about finding pairs, detecting cycles, or analyzing sequences? -2. **Choose the Right Technique**: Converging for relationships, fast/slow for detection, sliding for sequences -3. **Leverage Sorted Data**: When data is ordered, two-pointers become incredibly powerful -4. **Think in Terms of Efficiency**: Transform O(nΒ²) brute force into elegant O(n) solutions +## Why This Works -### 🌟 **From Librarian to Algorithm Expert** +Because the list is sorted, moving pointers inward removes impossible options. -Eleanor started the day as an organized librarian with intuitive problem-solving skills. By evening, she's mastered one of computer science's most versatile algorithmic patterns. Her bookmark techniques have revealed the elegant mathematics underlying efficient data processing. +Brute force: O(nΒ²) -"The beautiful thing," Eleanor tells her reflection in the library's front window, "is that these same principles apply whether you're organizing books, analyzing data streams, or solving complex computational problems. Once you understand the three pillars of two-pointer techniques, you can efficiently tackle a vast range of algorithmic challenges." +Two pointers: O(n) -The library may be closed, but Eleanor's journey into algorithmic thinking has just begun. Tomorrow brings new challenges, and she's ready to meet them with her powerful two-pointer toolkit. +Space: O(1) -*Ready for the next adventure? Let's see how Eleanor applies these techniques to even more complex problems in advanced data structures...* \ No newline at end of file +One pass. No nested loops. Efficient and clean. \ No newline at end of file diff --git a/src/sections/04-arrays-and-two-pointers/07-two-pointers/solution.js b/src/sections/04-arrays-and-two-pointers/07-two-pointers/solution.js deleted file mode 100644 index e703a46..0000000 --- a/src/sections/04-arrays-and-two-pointers/07-two-pointers/solution.js +++ /dev/null @@ -1,221 +0,0 @@ -// ============================== -// Exercise 1: Help Eleanor Find Book Pairs -// ============================== -// Task: Find two books whose publication years sum to a target year - -function findBookPairForTargetYear(bookYears, targetYear) { - let leftBookmark = 0; - let rightBookmark = bookYears.length - 1; - - while (leftBookmark < rightBookmark) { - const leftYear = bookYears[leftBookmark]; - const rightYear = bookYears[rightBookmark]; - const combinedYear = leftYear + rightYear; - - if (combinedYear === targetYear) { - return { - leftBook: { position: leftBookmark, year: leftYear }, - rightBook: { position: rightBookmark, year: rightYear }, - message: `Perfect! Books from ${leftYear} and ${rightYear} sum to ${targetYear}` - }; - } else if (combinedYear < targetYear) { - leftBookmark++; - } else { - rightBookmark--; - } - } - - return null; -} - -const libraryBooks = [1920, 1945, 1960, 1975, 1980, 1995, 2000, 2010]; -console.log("Finding pair for 1995:", findBookPairForTargetYear(libraryBooks, 1995)); -console.log("Finding pair for 2020:", findBookPairForTargetYear(libraryBooks, 2020)); - -// ============================== -// Exercise 2: Help Eleanor Detect Patterns -// ============================== -// Task: Find the middle book in a reading list and detect if a list has cycles - -function findMiddleBookInList(bookList) { - if (bookList.length === 0) { - return { message: "Empty list has no middle!" }; - } - - let slowPointer = 0; - let fastPointer = 0; - - while (fastPointer + 1 < bookList.length) { - slowPointer++; - fastPointer += 2; - } - - return { - middleBook: bookList[slowPointer], - position: slowPointer, - totalBooks: bookList.length, - message: `Middle book is "${bookList[slowPointer]}" at position ${slowPointer}` - }; -} - -function hasDuplicateInSortedList(sortedBooks) { - if (sortedBooks.length <= 1) { - return false; - } - - for (let i = 1; i < sortedBooks.length; i++) { - if (sortedBooks[i] === sortedBooks[i - 1]) { - return true; - } - } - - return false; -} - -const readingList = ["Book A", "Book B", "Book C", "Book D", "Book E"]; -const sortedBooks = ["Animal Farm", "Animal Farm", "Dune", "Foundation"]; -console.log("Middle book:", findMiddleBookInList(readingList)); -console.log("Has duplicates:", hasDuplicateInSortedList(sortedBooks)); - -// ============================== -// Exercise 3: Help Eleanor Analyze Book Sequences -// ============================== -// Task: Find the best consecutive sequence of books based on popularity scores - -function findBestBookSequence(popularityScores, sequenceLength) { - if (sequenceLength > popularityScores.length) { - return { message: "Sequence length larger than array!" }; - } - - let windowSum = 0; - let maxSum = 0; - let bestWindowStart = 0; - - // Calculate sum of first window - for (let i = 0; i < sequenceLength; i++) { - windowSum += popularityScores[i]; - } - maxSum = windowSum; - - // Slide the window across the array - for (let windowEnd = sequenceLength; windowEnd < popularityScores.length; windowEnd++) { - windowSum = windowSum - popularityScores[windowEnd - sequenceLength] + popularityScores[windowEnd]; - - if (windowSum > maxSum) { - maxSum = windowSum; - bestWindowStart = windowEnd - sequenceLength + 1; - } - } - - return { - startIndex: bestWindowStart, - totalPopularity: maxSum, - sequence: popularityScores.slice(bestWindowStart, bestWindowStart + sequenceLength) - }; -} - -function findShortestSequenceAboveThreshold(scores, threshold) { - let windowStart = 0; - let windowSum = 0; - let minLength = Infinity; - let bestStart = 0; - let bestLength = 0; - - for (let windowEnd = 0; windowEnd < scores.length; windowEnd++) { - windowSum += scores[windowEnd]; - - while (windowSum >= threshold && windowStart <= windowEnd) { - const currentLength = windowEnd - windowStart + 1; - - if (currentLength < minLength) { - minLength = currentLength; - bestStart = windowStart; - bestLength = currentLength; - } - - windowSum -= scores[windowStart]; - windowStart++; - } - } - - if (minLength === Infinity) { - return { message: `No sequence found with sum above ${threshold}` }; - } - - return { - length: minLength, - startPosition: bestStart, - sequence: scores.slice(bestStart, bestStart + bestLength), - totalSum: scores.slice(bestStart, bestStart + bestLength).reduce((a, b) => a + b, 0) - }; -} - -const bookPopularity = [2, 1, 4, 9, 3, 7, 5, 8, 6]; -console.log("Best sequence of 3:", findBestBookSequence(bookPopularity, 3)); -console.log("Shortest above 15:", findShortestSequenceAboveThreshold(bookPopularity, 15)); - -// ============================== -// Exercise 4: Help Eleanor Solve Palindrome Mysteries -// ============================== -// Task: Check if book titles are palindromes and find the longest palindromic substring - -function isPalindrome(text) { - // Clean the text: remove spaces and convert to lowercase - const cleanText = text.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); - - let leftBookmark = 0; - let rightBookmark = cleanText.length - 1; - - while (leftBookmark < rightBookmark) { - if (cleanText[leftBookmark] !== cleanText[rightBookmark]) { - return false; - } - leftBookmark++; - rightBookmark--; - } - - return true; -} - -function longestPalindromicSubstring(text) { - const cleanText = text.replace(/[^a-zA-Z0-9]/g, '').toLowerCase(); - let longest = ""; - - // Check for odd-length palindromes (center is a single character) - for (let center = 0; center < cleanText.length; center++) { - let left = center; - let right = center; - - while (left >= 0 && right < cleanText.length && cleanText[left] === cleanText[right]) { - const currentPalindrome = cleanText.slice(left, right + 1); - if (currentPalindrome.length > longest.length) { - longest = currentPalindrome; - } - left--; - right++; - } - } - - // Check for even-length palindromes (center is between two characters) - for (let center = 0; center < cleanText.length - 1; center++) { - let left = center; - let right = center + 1; - - while (left >= 0 && right < cleanText.length && cleanText[left] === cleanText[right]) { - const currentPalindrome = cleanText.slice(left, right + 1); - if (currentPalindrome.length > longest.length) { - longest = currentPalindrome; - } - left--; - right++; - } - } - - return longest; -} - -const mysteryTitles = ["A Santa at NASA", "Racecar", "Hello World", "Madam"]; -mysteryTitles.forEach(title => { - console.log(`"${title}" is palindrome: ${isPalindrome(title)}`); -}); -console.log("Longest palindrome in 'A Santa at NASA':", longestPalindromicSubstring("A Santa at NASA")); \ No newline at end of file diff --git a/src/sections/04-arrays-and-two-pointers/07-two-pointers/starterCode.js b/src/sections/04-arrays-and-two-pointers/07-two-pointers/starterCode.js deleted file mode 100644 index f03ac6a..0000000 --- a/src/sections/04-arrays-and-two-pointers/07-two-pointers/starterCode.js +++ /dev/null @@ -1,74 +0,0 @@ -// ============================== -// Exercise 1: Help Eleanor Find Book Pairs -// ============================== -// Task: Find two books whose publication years sum to a target year - -// function findBookPairForTargetYear(bookYears, targetYear) { -// // Use converging pointers to find a pair that sums to targetYear -// // Return an object with the pair information or null if not found -// } - -// const libraryBooks = [1920, 1945, 1960, 1975, 1980, 1995, 2000, 2010]; -// console.log("Finding pair for 1995:", findBookPairForTargetYear(libraryBooks, 1995)); -// console.log("Finding pair for 2020:", findBookPairForTargetYear(libraryBooks, 2020)); - -// ============================== -// Exercise 2: Help Eleanor Detect Patterns -// ============================== -// Task: Find the middle book in a reading list and detect if a list has cycles - -// function findMiddleBookInList(bookList) { -// // Use fast and slow pointers to find the middle book -// // Return the middle book and its position -// } - -// function hasDuplicateInSortedList(sortedBooks) { -// // Use two pointers to detect if there are consecutive duplicates -// // Return true if duplicates found, false otherwise -// } - -// const readingList = ["Book A", "Book B", "Book C", "Book D", "Book E"]; -// const sortedBooks = ["Animal Farm", "Animal Farm", "Dune", "Foundation"]; -// console.log("Middle book:", findMiddleBookInList(readingList)); -// console.log("Has duplicates:", hasDuplicateInSortedList(sortedBooks)); - -// ============================== -// Exercise 3: Help Eleanor Analyze Book Sequences -// ============================== -// Task: Find the best consecutive sequence of books based on popularity scores - -// function findBestBookSequence(popularityScores, sequenceLength) { -// // Use sliding window to find the sequence with highest total popularity -// // Return the starting index and total popularity score -// } - -// function findShortestSequenceAboveThreshold(scores, threshold) { -// // Use dynamic sliding window to find shortest sequence above threshold -// // Return the length and starting position of the shortest sequence -// } - -// const bookPopularity = [2, 1, 4, 9, 3, 7, 5, 8, 6]; -// console.log("Best sequence of 3:", findBestBookSequence(bookPopularity, 3)); -// console.log("Shortest above 15:", findShortestSequenceAboveThreshold(bookPopularity, 15)); - -// ============================== -// Exercise 4: Help Eleanor Solve Palindrome Mysteries -// ============================== -// Task: Check if book titles are palindromes and find the longest palindromic substring - -// function isPalindrome(text) { -// // Use converging pointers to check if text reads the same forwards and backwards -// // Ignore spaces, punctuation, and case -// // Return true if palindrome, false otherwise -// } - -// function longestPalindromicSubstring(text) { -// // Find the longest substring that is a palindrome -// // Return the palindromic substring -// } - -// const mysteryTitles = ["A Santa at NASA", "Racecar", "Hello World", "Madam"]; -// mysteryTitles.forEach(title => { -// console.log(`"${title}" is palindrome: ${isPalindrome(title)}`); -// }); -// console.log("Longest palindrome in 'A Santa at NASA':", longestPalindromicSubstring("A Santa at NASA")); \ No newline at end of file diff --git a/src/sections/04-arrays-and-two-pointers/07-two-pointers/tests.js b/src/sections/04-arrays-and-two-pointers/07-two-pointers/tests.js deleted file mode 100644 index 31841f7..0000000 --- a/src/sections/04-arrays-and-two-pointers/07-two-pointers/tests.js +++ /dev/null @@ -1,342 +0,0 @@ -export const tests = [ - { - name: "Test Exercise 1: findBookPairForTargetYear function", - test: (code) => { - try { - const testCode = code + ` - // Test findBookPairForTargetYear function - if (typeof findBookPairForTargetYear === 'function') { - const bookYears = [1920, 1945, 1960, 1975, 1980, 1995, 2000, 2010]; - - const result1 = findBookPairForTargetYear(bookYears, 1995); - const result2 = findBookPairForTargetYear(bookYears, 3955); - const result3 = findBookPairForTargetYear(bookYears, 1800); - const result4 = findBookPairForTargetYear([], 2000); - const result5 = findBookPairForTargetYear([2000], 2000); - - return { result1, result2, result3, result4, result5, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "findBookPairForTargetYear function not found. Make sure to uncomment and implement it." }; - } - - if (!testResult.result1 || testResult.result1.leftBook.year + testResult.result1.rightBook.year !== 1995) { - return { passed: false, message: "Should find a pair for 1995" }; - } - if (!testResult.result2 || testResult.result2.leftBook.year + testResult.result2.rightBook.year !== 3955) { - return { passed: false, message: "Should find a pair for 3955" }; - } - if (testResult.result3 !== null) { - return { passed: false, message: "Should return null when no pair found" }; - } - if (testResult.result4 !== null) { - return { passed: false, message: "Should return null for empty array" }; - } - if (testResult.result5 !== null) { - return { passed: false, message: "Should return null for single element array" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "findBookPairForTargetYear should find pairs that sum to target year using converging pointers" - }, - { - name: "Test Exercise 2a: findMiddleBookInList function", - test: (code) => { - try { - const testCode = code + ` - // Test findMiddleBookInList function - if (typeof findMiddleBookInList === 'function') { - const oddList = ["Book A", "Book B", "Book C", "Book D", "Book E"]; - const evenList = ["Book A", "Book B", "Book C", "Book D"]; - const singleList = ["Only Book"]; - const emptyList = []; - - const result1 = findMiddleBookInList(oddList); - const result2 = findMiddleBookInList(evenList); - const result3 = findMiddleBookInList(singleList); - const result4 = findMiddleBookInList(emptyList); - - return { result1, result2, result3, result4, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "findMiddleBookInList function not found. Make sure to uncomment and implement it." }; - } - - if (testResult.result1.middleBook !== "Book C" || testResult.result1.position !== 2) { - return { passed: false, message: 'Middle of odd list should be "Book C" at position 2' }; - } - if (testResult.result2.middleBook !== "Book B" || testResult.result2.position !== 1) { - return { passed: false, message: 'Middle of even list should be "Book B" at position 1' }; - } - if (testResult.result3.middleBook !== "Only Book" || testResult.result3.position !== 0) { - return { passed: false, message: 'Single element should be the middle at position 0' }; - } - if (!testResult.result4.message || !testResult.result4.message.includes("Empty")) { - return { passed: false, message: "Should handle empty list" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "findMiddleBookInList should find middle element using fast and slow pointers" - }, - { - name: "Test Exercise 2b: hasDuplicateInSortedList function", - test: (code) => { - try { - const testCode = code + ` - // Test hasDuplicateInSortedList function - if (typeof hasDuplicateInSortedList === 'function') { - const withDuplicates = ["Animal Farm", "Animal Farm", "Dune", "Foundation"]; - const withoutDuplicates = ["Animal Farm", "Dune", "Foundation", "The Hobbit"]; - const emptyList = []; - const singleList = ["Book"]; - const allSame = ["Book", "Book", "Book"]; - - const result1 = hasDuplicateInSortedList(withDuplicates); - const result2 = hasDuplicateInSortedList(withoutDuplicates); - const result3 = hasDuplicateInSortedList(emptyList); - const result4 = hasDuplicateInSortedList(singleList); - const result5 = hasDuplicateInSortedList(allSame); - - return { result1, result2, result3, result4, result5, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "hasDuplicateInSortedList function not found. Make sure to uncomment and implement it." }; - } - - if (testResult.result1 !== true) { - return { passed: false, message: "Should detect duplicates" }; - } - if (testResult.result2 !== false) { - return { passed: false, message: "Should not detect duplicates when none exist" }; - } - if (testResult.result3 !== false) { - return { passed: false, message: "Empty list should have no duplicates" }; - } - if (testResult.result4 !== false) { - return { passed: false, message: "Single element should have no duplicates" }; - } - if (testResult.result5 !== true) { - return { passed: false, message: "Should detect duplicates in all-same list" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "hasDuplicateInSortedList should detect consecutive duplicates in sorted arrays" - }, - { - name: "Test Exercise 3a: findBestBookSequence function", - test: (code) => { - try { - const testCode = code + ` - // Test findBestBookSequence function - if (typeof findBestBookSequence === 'function') { - const popularity = [2, 1, 4, 9, 3, 7, 5, 8, 6]; - - const result1 = findBestBookSequence(popularity, 3); - const result2 = findBestBookSequence(popularity, 1); - const result3 = findBestBookSequence(popularity, 15); - const result4 = findBestBookSequence(popularity, popularity.length); - - return { result1, result2, result3, result4, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "findBestBookSequence function not found. Make sure to uncomment and implement it." }; - } - - if (testResult.result1.totalPopularity !== 20 || testResult.result1.startIndex !== 5) { - return { passed: false, message: "Best sequence of 3 should have sum 20 starting at index 5" }; - } - if (testResult.result2.totalPopularity !== 9 || testResult.result2.startIndex !== 3) { - return { passed: false, message: "Best single element should be 9 at index 3" }; - } - if (!testResult.result3.message || !testResult.result3.message.includes("larger")) { - return { passed: false, message: "Should handle sequence longer than array" }; - } - - const expectedSum = [2, 1, 4, 9, 3, 7, 5, 8, 6].reduce((a, b) => a + b, 0); - if (testResult.result4.totalPopularity !== expectedSum) { - return { passed: false, message: "Full array should sum to total" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "findBestBookSequence should find maximum sum subarray of fixed size using sliding window" - }, - { - name: "Test Exercise 3b: findShortestSequenceAboveThreshold function", - test: (code) => { - try { - const testCode = code + ` - // Test findShortestSequenceAboveThreshold function - if (typeof findShortestSequenceAboveThreshold === 'function') { - const scores = [2, 1, 4, 9, 3, 7, 5, 8, 6]; - - const result1 = findShortestSequenceAboveThreshold(scores, 15); - const result2 = findShortestSequenceAboveThreshold(scores, 25); - const totalSum = scores.reduce((a, b) => a + b, 0); - const result3 = findShortestSequenceAboveThreshold(scores, totalSum + 1); - const result4 = findShortestSequenceAboveThreshold(scores, 0); - - return { result1, result2, result3, result4, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "findShortestSequenceAboveThreshold function not found. Make sure to uncomment and implement it." }; - } - - if (testResult.result1.length < 1 || testResult.result1.totalSum < 15) { - return { passed: false, message: "Should find a sequence with sum >= 15" }; - } - if (testResult.result2.length < 3 || testResult.result2.totalSum < 25) { - return { passed: false, message: "Should need at least 3 elements for sum >= 25" }; - } - if (!testResult.result3.message || !testResult.result3.message.includes("No sequence")) { - return { passed: false, message: "Should handle impossible threshold" }; - } - if (testResult.result4.length !== 1) { - return { passed: false, message: "Threshold 0 should return single element" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "findShortestSequenceAboveThreshold should find minimum length subarray with sum above threshold" - }, - { - name: "Test Exercise 4a: isPalindrome function", - test: (code) => { - try { - const testCode = code + ` - // Test isPalindrome function - if (typeof isPalindrome === 'function') { - const tests = [ - { text: "Racecar", expected: true }, - { text: "Madam", expected: true }, - { text: "A Santa at NASA", expected: true }, - { text: "A man a plan a canal Panama", expected: true }, - { text: "Hello World", expected: false }, - { text: "The Great Gatsby", expected: false }, - { text: "", expected: true }, - { text: "a", expected: true }, - { text: "aa", expected: true }, - { text: "ab", expected: false } - ]; - - const results = tests.map(test => ({ - text: test.text, - result: isPalindrome(test.text), - expected: test.expected - })); - - return { results, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "isPalindrome function not found. Make sure to uncomment and implement it." }; - } - - for (const test of testResult.results) { - if (test.result !== test.expected) { - return { passed: false, message: `"${test.text}" should ${test.expected ? 'be' : 'not be'} a palindrome` }; - } - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "isPalindrome should detect palindromes using converging pointers, ignoring spaces and case" - }, - { - name: "Test Exercise 4b: longestPalindromicSubstring function", - test: (code) => { - try { - const testCode = code + ` - // Test longestPalindromicSubstring function - if (typeof longestPalindromicSubstring === 'function') { - const result1 = longestPalindromicSubstring("A Santa at NASA"); - const result2 = longestPalindromicSubstring("abcdef"); - const result3 = longestPalindromicSubstring("racecar"); - const result4 = longestPalindromicSubstring(""); - const result5 = longestPalindromicSubstring("abccba"); - - return { result1, result2, result3, result4, result5, hasFunction: true }; - } - return { hasFunction: false }; - `; - - const testResult = new Function(testCode)(); - - if (!testResult.hasFunction) { - return { passed: false, message: "longestPalindromicSubstring function not found. Make sure to uncomment and implement it." }; - } - - if (testResult.result1.length < 3) { - return { passed: false, message: "Should find a palindrome of at least length 3 in 'A Santa at NASA'" }; - } - if (testResult.result2.length !== 1) { - return { passed: false, message: "Should find single character palindrome in 'abcdef'" }; - } - if (testResult.result3 !== "racecar") { - return { passed: false, message: "Should find the entire string as palindrome in 'racecar'" }; - } - if (testResult.result4 !== "") { - return { passed: false, message: "Empty string should return empty string" }; - } - if (testResult.result5 !== "abccba") { - return { passed: false, message: "Should find even-length palindrome in 'abccba'" }; - } - - return { passed: true }; - } catch (error) { - return { passed: false, message: error.message }; - } - }, - message: "longestPalindromicSubstring should find the longest palindromic substring" - } -]; \ No newline at end of file