Skip to content

learn: solve Reverse Words in a String II (#186) via guided TDD#235

Merged
pertrai1 merged 6 commits into
mainfrom
tdd/0186-reverse-words-in-a-string-ii
Feb 12, 2026
Merged

learn: solve Reverse Words in a String II (#186) via guided TDD#235
pertrai1 merged 6 commits into
mainfrom
tdd/0186-reverse-words-in-a-string-ii

Conversation

@pertrai1

@pertrai1 pertrai1 commented Feb 12, 2026

Copy link
Copy Markdown
Owner

Problem

Reverse Words in a String II — Medium

Approach

Two-step reversal algorithm using two pointers:

  1. Reverse the entire array to get words in reversed order (but characters backwards)
  2. Find and reverse each individual word to fix character order

Complexity

  • Time: O(n) — Two linear passes through the array
  • Space: O(1) — Constant space (in-place modification with pointer variables)

Pattern

Two-Pointer (applied twice — once for entire array, once per word)

Learning Summary

  • Mode: Coach (learner wrote all implementation code)
  • Cycles: 5 guided cycles (L1 → L2 → L3 test ownership progression)
  • Tests: 5 test cases (empty array, single-char words, multi-char words, single word, main example)
  • Hint Levels Used: Level 2 hints in cycle 2 (algorithm structure after multiple debugging attempts)
  • Key Insight: Reverse entire array first, then reverse each word individually
  • Pattern Checkpoints: 2/2 correct (with minor .length complexity correction)

🧠 Self-Review Questions

  1. Why does the two-step reversal algorithm work? What would happen if you only did step 1 or only step 2?
Answer The two-step approach works because reversing the entire array gets the words in the correct final order, but with each word's characters backwards. Reversing each word individually then fixes the character order within each word. If you only did step 1, the words would be in the right order but backwards ("eht yks si eulb"). If you only did step 2, the words would stay in the original order (no word-order reversal).
2. What's the time complexity analysis? Does reversing twice make it O(n²)?
Answer No, it's still O(n). Step 1 visits each character once (O(n)). Step 2 visits each character once while scanning and reversing words (O(n)). Total: O(n) + O(n) = O(2n) = O(n) linear time.

Files

  • README.md — Problem statement
  • reverse-words-in-a-string-ii.ts — Solution
  • reverse-words-in-a-string-ii.test.ts — Test suite (5 tests)
  • POST_MORTEM.md — Interview debrief and learning analysis

Summary by CodeRabbit

  • New Features

    • Added solution for LeetCode problem 0186: Reverse Words in a String II with in-place word reversal algorithm
  • Documentation

    • Added README documentation for problem 0186
    • Added interview debrief post-mortem with detailed analysis and feedback
  • Tests

    • Added comprehensive test suite covering multiple scenarios and edge cases

@pertrai1 pertrai1 added the code challenge this is a coding challenge label Feb 12, 2026
@github-actions

github-actions Bot commented Feb 12, 2026

Copy link
Copy Markdown

Claude finished @pertrai1's task in 1m 33s —— View job


PR Review Complete ✅

Reviewing LeetCode #186 - Reverse Words in a String II (TDD learning exercise)

Review Checklist

  • Read all changed files
  • Verify algorithm correctness
  • Validate complexity analysis
  • Assess code quality
  • Identify patterns and key insights
  • Suggest related problems
  • Provide learning summary

1. Algorithm Correctness ✅

The solution correctly implements the two-step reversal algorithm:

  1. Step 1: Reverse entire array → ["blue"," ","is"," ","sky"," ","the"] (words backwards, chars backwards)
  2. Step 2: Reverse each word → ["blue"," ","is"," ","sky"," ","the"] (words backwards, chars correct)

Edge cases verified (reverse-words-in-a-string-ii.test.ts:5-36):

  • ✅ Empty array (lines 5-9)
  • ✅ Single-character words (lines 11-15)
  • ✅ Multi-character words (lines 17-22)
  • ✅ Single word with no spaces (lines 24-29)
  • ✅ Main example with 4 words (lines 31-36)

All test cases are well-structured and pass successfully. The solution handles all constraints correctly (no leading/trailing spaces, single spaces between words).


2. Complexity Analysis ✅

Time Complexity: O(n) — CORRECT ✅

The PR description claims O(n), which is accurate:

  • Step 1 (reverse-words-in-a-string-ii.ts:10-14): O(n) — each character visited once
  • Step 2 (reverse-words-in-a-string-ii.ts:19-36): O(n) — each character visited once while scanning and reversing words
  • Total: O(n) + O(n) = O(2n) = O(n) linear time

Space Complexity: O(1) — CORRECT ✅

The solution modifies the array in-place using only pointer variables (left, right, i, start, end). No additional data structures are allocated.


3. Code Quality 🌟

Strengths:

  • Clean variable naming: left, right, start, end are intuitive
  • Modern JavaScript: Uses destructuring for swaps: [s[left], s[right]] = [s[right], s[left]] (reverse-words-in-a-string-ii.ts:11, 33)
  • Clear structure: Two steps are well-separated with comments (lines 6, 16)
  • Edge case handling: Early return for empty array (line 4)
  • TypeScript types: Proper string[] typing and void return type

Minor observations:

  • The three-loop structure in Step 2 is a classic pattern for processing words with boundaries
  • Loop invariants are maintained correctly:
    • Step 1: left < right ensures we don't swap the same element twice
    • Step 2: start < end ensures proper word reversal

No issues found — the code adheres to all CLAUDE.md guidelines for LeetCode solutions.


4. Pattern Recognition & Key Insight

Pattern: Two-Pointer (applied twice)

Why this pattern is suitable:

  • The problem requires in-place modification (O(1) space constraint from the follow-up)
  • Array reversal is a classic two-pointer operation
  • The pattern is applied at two different scopes: entire array, then individual words

Key Insight 💡

The crucial realization is that you can achieve word-order reversal by:

  1. First reversing everything → gets words in correct order but with backwards characters
  2. Then reversing each word individually → fixes the character order

This is counterintuitive because you're temporarily making the array "worse" (all characters backwards) before making it correct.

Why it works:

  • Reversing the entire array moves the last word to the front, but backwards: "eht yks si eulb""eulb si yks eht"
  • Reversing each word then flips the characters back: "blue is sky the"

This is more efficient than trying to move words directly, which would require complex index calculations or extra space.


5. Related Problems for Practice

To strengthen the two-pointer reversal pattern and word-boundary detection:

  1. 151. Reverse Words in a String — Medium
    Same problem but with string input/output instead of char[]. Requires handling multiple spaces, leading/trailing spaces. Great follow-up to practice the same algorithm with different constraints.

  2. 557. Reverse Words in a String III — Easy
    Reverse characters in each word but keep word order (opposite of this problem). Practices word-boundary detection without the full array reversal step.

  3. 189. Rotate Array — Medium
    Uses a three-reversal technique similar to this problem:

    • Reverse [0, k), reverse [k, n), reverse [0, n) to rotate by k positions
    • Reinforces the "reverse multiple times" pattern
  4. 344. Reverse String — Easy
    Simpler two-pointer reversal practice. Good warmup before tackling multi-step problems.


6. Alternative Approaches

Approach 1: Split, Reverse, Join (Not In-Place)

function reverseWords(s: string[]): void {
  const words = s.join('').split(' ').reverse();
  s.splice(0, s.length, ...words.join(' ').split(''));
}

Trade-offs:

  • Space: O(n) for the intermediate arrays/strings
  • Simplicity: More readable, uses built-in methods
  • Violates constraint: The follow-up explicitly asks for O(1) space

Approach 2: Direct Word Swapping

Identify word boundaries, then swap entire words using temporary storage.

Trade-offs:

  • Complexity: More complex boundary logic
  • Space: Requires temporary storage for words
  • Conceptually simpler: Directly swaps words rather than reversing twice

Verdict: The two-step reversal approach (current solution) is optimal for this problem's constraints.


Learning Summary 🎓

What Makes This Problem Educational

  1. Counterintuitive Algorithm: The solution temporarily makes things "worse" (reversing everything) before fixing them (reversing each word). This teaches thinking in steps rather than direct manipulation.

  2. Nested Loop Pattern: Step 2's three-loop structure (skip spaces → find word → reverse word) is a fundamental pattern for processing bounded regions in arrays.

  3. In-Place Manipulation: Demonstrates how to achieve O(1) space by using pointers instead of creating new data structures.

  4. Pattern Composition: Shows how to apply the same pattern (two-pointer reversal) at different scopes (entire array vs. individual words).

Common Mistakes to Watch For

  1. Off-by-one errors: Setting end = i instead of end = i - 1 (POST_MORTEM.md mentions this bug was caught during TDD cycle 2)
  2. Variable initialization: Using start = 0 instead of start = i when finding word boundaries
  3. Forgetting to skip spaces: Not handling the space-skipping loop before finding the word start
  4. Misunderstanding the problem: Confusing "reverse words" with "reverse characters in words"

TDD Learning Context

The POST_MORTEM.md reveals valuable insights about the learning journey:

  • 5 TDD cycles progressed from simple (empty array) to complex (main example)
  • Level 2 hints were needed in cycle 2 for the algorithm structure
  • Test ownership progression: L1 → L1 → L2 → L2 → L3 (showing growth in autonomy)
  • Pattern checkpoint: 2/2 correct (with minor .length complexity correction)

This demonstrates effective use of TDD to build understanding incrementally.


Final Verdict

Excellent work! ✅ This solution correctly implements the optimal algorithm with clean, readable code. The test suite is comprehensive, and the POST_MORTEM.md provides valuable reflection on the learning process. The solution demonstrates solid understanding of the two-pointer pattern and in-place array manipulation.

No changes needed — the code is ready to merge.


@pertrai1

Copy link
Copy Markdown
Owner Author

💡 Educational Note: Two-Step Reversal Pattern

This solution demonstrates a classic two-step reversal pattern that's used in several array rotation and word reversal problems.

Why it works:

  1. Step 1 (lines 7-14): Reversing the entire array puts the words in the correct final order, but each word's characters are backwards

    • Example: ["t","h","e"," ","s","k","y"]["y","k","s"," ","e","h","t"] ("yks eht")
  2. Step 2 (lines 17-37): Reversing each individual word fixes the character order within each word

    • Example: ["y","k","s"," ","e","h","t"]["s","k","y"," ","t","h","e"] ("sky the")

Related problems using this pattern:

@github-actions

Copy link
Copy Markdown

✅ Test Results

Tests have been executed for this pull request.

📊 Coverage Summary

Metric Coverage
Statements 94.27%
Branches 90.76%
Functions 87.5%
Lines 94.21%

Check the workflow logs for detailed test output.

@coderabbitai

coderabbitai Bot commented Feb 12, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds a complete new LeetCode problem entry for "0186 - Reverse Words in a String II" (Medium difficulty). The contribution includes the problem documentation, a post-mortem interview debrief, a full test suite, and an implementation using a two-step reversal algorithm (full array reversal followed by per-word character reversals).

Changes

Cohort / File(s) Summary
Documentation Index
docs/PROBLEMS.md
Added two entries for problem 0186 in the Medium section and Two Pointers pattern subsection.
Problem Documentation
leetcode/medium/0186-reverse-words-in-a-string-ii/README.md, POST_MORTEM.md
Added problem description, constraints, example, and structured interview post-mortem with scoring and coaching feedback.
Implementation & Tests
leetcode/medium/0186-reverse-words-in-a-string-ii/reverse-words-in-a-string-ii.ts, reverse-words-in-a-string-ii.test.ts
Added in-place reversal algorithm implementation and Vitest suite covering five test cases (empty input, single/multiple words, edge cases).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Two passes through the character array,
First the whole, then word-by-word we sway,
Spaces guide us where to stop and start,
A elegant in-place reversal art! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'learn: solve Reverse Words in a String II (#186) via guided TDD' accurately summarizes the main change—adding a complete solution to LeetCode problem 186 using test-driven development with a two-pointer approach. It is clear, specific, and directly reflects the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tdd/0186-reverse-words-in-a-string-ii

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
leetcode/medium/0186-reverse-words-in-a-string-ii/reverse-words-in-a-string-ii.ts (1)

1-38: Add complexity and pattern documentation as code comments.

Per coding guidelines, LeetCode solution files should document both time/space complexity in Big O notation and the algorithmic pattern used.

📝 Suggested comment additions
+/**
+ * Pattern: Two-Pointer (applied twice)
+ * Time: O(n) — two linear passes over the array
+ * Space: O(1) — in-place swaps, constant extra variables
+ */
 export function reverseWords(s: string[]): void {

As per coding guidelines: "Always document both time and space complexity in Big O notation with clear reasoning" and "Document the algorithmic pattern used in solution code comments".

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pertrai1

Copy link
Copy Markdown
Owner Author

💡 Educational Note: TypeScript Destructuring Swap

[s[left], s[right]] = [s[right], s[left]];

This elegant one-liner swaps two array elements without needing a temporary variable.

How it works:

  1. Right side creates a temporary array: [s[right], s[left]]
  2. Left side destructures that array into the original positions: s[left] gets the first element (old s[right]), s[right] gets the second element (old s[left])

Traditional approach (for comparison):

const temp = s[left];
s[left] = s[right];
s[right] = temp;

Both approaches work, but destructuring is more concise and readable. The performance is essentially identical in modern JavaScript engines.

@github-actions

Copy link
Copy Markdown

🤖 Gemini Code Review (Model: gemini-2.5-flash)

Here's a detailed review of the provided LeetCode solution for "Reverse Words in a String II":


1. Pattern Identification

This solution primarily uses the Two Pointers pattern. It applies this pattern in two distinct phases:

  1. Global Reversal: Two pointers (left and right) are used to reverse the entire character array.
  2. Word-by-Word Reversal: A single pointer (i) iterates through the array to identify word boundaries. For each word found, two internal pointers (start and end) are used to reverse the characters within that specific word.

The overall strategy is a classic "three-reversal" technique often used for problems requiring in-place rotation or rearrangement of segments.

2. Complexity Verification

  • Time Complexity: O(N)

    • Stated Accuracy: The POST_MORTEM.md correctly identifies O(N).
    • Verification:
      • Step 1 (Reverse entire array): The while (left < right) loop iterates roughly N/2 times, touching each character once for a swap. This is O(N).
      • Step 2 (Reverse each word): The outer while (i < length) loop iterates through the entire array once. Inside this loop, i advances to skip spaces, then to find the end of a word. The inner while (start < end) loop reverses characters within a word. Critically, each character in the array is part of exactly one word (or a space). When reversing words, each character is visited a constant number of times (once by the outer i pointer, and then at most twice by the inner start/end pointers during its word's reversal). Therefore, this step is also O(N).
      • Total: O(N) + O(N) = O(N). The stated complexity is accurate.
  • Space Complexity: O(1)

    • Stated Accuracy: The POST_MORTEM.md correctly identifies O(1).
    • Verification: The solution modifies the input array s directly (in-place) without allocating any additional data structures whose size depends on the input N. It only uses a few constant variables (length, left, right, i, start, end). The stated complexity is accurate.

3. Key Insight

The key insight, often called the "three-reversal" technique, is:

  1. Reverse the entire sequence: This puts the "words" in the correct order, but each word's characters are individually reversed. For example, "the sky" becomes "yks eht".
  2. Reverse each individual word: After the first step, iterate through the sequence, identify each word (delimited by spaces), and reverse the characters within that word. This corrects the character order for each word while maintaining the correct word order established in step 1. For "yks eht", reversing "yks" gives "sky", and reversing "eht" gives "the", resulting in "sky the".

This two-step process elegantly achieves the word reversal in-place with optimal time and space complexity.

4. Edge Case Analysis

The provided reverse-words-in-a-string-ii.test.ts covers several good edge cases:

  • Empty array: [] - Handled by if (length === 0) return;.
  • Two single-character words: ['b', ' ', 'a'] - Tests basic word reversal.
  • Multiple multi-character words: ['c', 'a', 't', ' ', 'd', 'o', 'g'] - Standard case.
  • Single word (no spaces): ['s', 'i', 'n', 'g', 'l', 'e'] - Correctly remains unchanged.
  • More than 2 words (main example): ['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'] - Comprehensive test.

Given the problem constraints (no leading/trailing spaces, words separated by single spaces, non-space characters for words), these test cases are quite thorough. The solution correctly handles all these scenarios.

Additional considerations (covered by constraints or existing tests):

  • An array with a single character (e.g., ['a']): Covered by the "single word" test.
  • An array consisting only of spaces (e.g., [' ', ' ', ' ']) could be an edge case if allowed, but constraints imply valid words exist. The current solution would handle it correctly by doing nothing, as there are no non-space characters to form words.

5. Learning Points

  • Similar problems using this pattern:

    • 189. Rotate Array: This problem uses the exact same three-reversal technique to rotate an array in-place. It's an excellent problem to solidify understanding of this pattern.
    • 344. Reverse String: The fundamental two-pointer reversal logic is the core of this problem.
    • 151. Reverse Words in a String: The non-in-place version where you might deal with multiple spaces, leading/trailing spaces, and return a new string. It helps practice parsing and manipulating strings.
    • 557. Reverse Words in a String III: Reverse characters within each word, but keep the original word order. This is essentially just "Step 2" of the current problem.
  • Common mistakes people make with this pattern:

    • Off-by-one errors: Especially when calculating start and end indices for word boundaries or during the reversal loops.
    • Incorrect loop conditions: Forgetting to increment/decrement pointers, leading to infinite loops or skipping elements.
    • Mismanaging space characters: Not correctly identifying the start/end of words due to spaces, or accidentally including spaces in word reversals.
    • Not handling the "in-place" requirement: Many initial attempts might use split(), reverse(), join() which are convenient but typically allocate O(N) extra space, violating the in-place constraint.
  • Variations of this problem:

    • Allow multiple spaces between words (e.g., "a b")
    • Allow leading or trailing spaces (e.g., " hello world ")
    • Return a new string/array instead of modifying in-place.
    • Reverse characters within words but keep word order (LeetCode 557).
    • Reverse a linked list in groups of K (uses a similar idea of reversing sub-sections).

6. Code Quality

The code quality is excellent:

  • Variable Naming: left, right, i, start, end, length, s are all standard, clear, and appropriate for their context.
  • Code Structure: The solution is very well-structured.
    • The early exit if (length === 0) return; is a good practice.
    • The two main steps are clearly separated by comments (// Step 1: Reverse the entire array and // Step 2: Reverse each individual word), which significantly enhances readability and understanding of the algorithm's logic.
  • Readability:
    • The use of ES6 destructuring for swaps ([s[left], s[right]] = [s[right], s[left]]) is modern, concise, and highly readable.
    • The while loops are clear and correctly manage pointer advancement.
  • TypeScript Best Practices:
    • const is used for length, and let for mutable pointers, adhering to best practices.
    • Type annotation s: string[] is correct.

Minor Improvement Suggestion:
For better modularity and reusability, the in-place reversal logic could be extracted into a small helper function. This isn't strictly necessary here as it's a simple, repeated pattern, but it's a good general practice.

function reverse(arr: string[], start: number, end: number): void {
  while (start < end) {
    [arr[start], arr[end]] = [arr[end], arr[start]];
    start++;
    end--;
  }
}

export function reverseWords(s: string[]): void {
  const length = s.length;
  if (length === 0) return;

  // Step 1: Reverse the entire array
  reverse(s, 0, length - 1);

  // Step 2: Reverse each individual word
  let i = 0;
  while (i < length) {
    while (i < length && s[i] === ' ') {
      i++;
    }
    let start = i; // Mark the beginning of the current word
    while (i < length && s[i] !== ' ') {
      i++;
    }
    let end = i - 1; // Mark the end of the current word
    reverse(s, start, end);
  }
}

This refactoring makes the reverseWords function even more declarative, clearly showing the two main steps without the inner loop details.

7. Alternative Approaches

  1. Using Built-in String Manipulation (Not In-Place):

    • Approach: If the "in-place" constraint was lifted, or if working with a language that makes string manipulation easier (e.g., Python's split(), reverse(), join()), one could convert the char[] to a string, split it by spaces, reverse the array of words, join them back with spaces, and then convert back to char[].
    • Trade-offs:
      • Pros: Much simpler and quicker to implement.
      • Cons: Typically O(N) space complexity due to creating intermediate string and array objects, violating the O(1) space constraint often imposed by "in-place" problems.
  2. Two-Pass with Manual Word Collection (Not In-Place):

    • Approach: Iterate through the character array, identify each word, collect these words into a temporary array (e.g., string[]). Then, reverse this temporary array of words and reconstruct the final char[] by appending words and spaces.
    • Trade-offs:
      • Pros: Conceptually straightforward for word identification.
      • Cons: O(N) space complexity for the temporary array of words. Requires building a new char[] or carefully modifying the original if allowed, but the "reconstruction" part is less elegant than the three-reversal method for in-place modification.

@github-actions

Copy link
Copy Markdown

🤖 Gemini Code Review (Model: gemini-2.5-flash)

This is a great solution demonstrating a classic in-place string manipulation pattern! Let's break it down.


1. Pattern Identification

This solution primarily uses the Two Pointers pattern. Specifically, it employs a variation known as the "Three-Reversal" or "Two-Step Reversal" technique.

The two-pointer technique is applied:

  1. To reverse the entire character array.
  2. To reverse each individual word within the character array.

2. Complexity Verification

  • Time Complexity: O(N)

    • Verification: The stated time complexity is accurate.
    • Explanation:
      • Step 1 (Reverse entire array): The while (left < right) loop iterates roughly N/2 times, where N is the length of the array. This is O(N).
      • Step 2 (Reverse each word): The outer while (i < length) loop iterates through the array once. Inside this loop, pointers i, start, and end traverse each character. Each character is visited a constant number of times: once or twice to find word boundaries, and once more to reverse the word it belongs to.
      • Since both steps are linear passes over the array, the total time complexity is O(N) + O(N) = O(N).
  • Space Complexity: O(1)

    • Verification: The stated space complexity is accurate.
    • Explanation: The solution modifies the input array s directly (in-place). It only uses a few constant-space variables (length, left, right, i, start, end) regardless of the input size. No auxiliary data structures that grow with N are allocated.

3. Key Insight

The key insight for solving "Reverse Words in a String II" in-place with O(1) space is the two-step reversal technique:

  1. Reverse the entire character array: This initial reversal puts the words in the correct final order, but each word itself is backwards.
    • Example: ["t","h","e"," ","s","k","y"] becomes ["y","k","s"," ","e","h","t"] (words "sky" then "the", but characters reversed).
  2. Reverse each individual word: After the first step, iterate through the array to identify the boundaries of each word (delimited by spaces). Then, apply the reversal technique again to the characters within each word. This corrects the characters within each word, completing the transformation.
    • Example continuing from above: ["y","k","s"," ","e","h","t"] becomes ["s","k","y"," ","t","h","e"].

This "aha!" moment is crucial because it transforms a seemingly complex word-level reversal into two simpler, character-level reversal operations that can both be done efficiently in-place.

4. Edge Case Analysis

The current test suite covers several important edge cases:

  • Empty array: []
  • Two single-character words: ['b', ' ', 'a']
  • Multiple multi-character words: ['c', 'a', 't', ' ', 'd', 'o', 'g']
  • Single word (no spaces): ['s', 'i', 'n', 'g', 'l', 'e']
  • Main example (multiple words): ['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e']

The solution correctly handles all these cases.

Potential additional edge cases (though some are covered by constraints):

  • Array with only spaces: [' ', ' ', ' ']. Given the problem constraints ("no leading or trailing spaces", "Words are separated by single spaces"), this input should not occur. If it were allowed, the current solution would correctly return [' ', ' ', ' '].
  • A single space: [' ']. Similar to the above, constraints imply valid words. If allowed, the solution would return [' '].
  • Words of varying lengths: This is well-covered by existing tests.

The current solution is robust for the problem's stated constraints.

5. Learning Points

  • Similar problems using this same pattern:

    • 344. Reverse String: The fundamental building block – reversing an entire array/string in-place using two pointers.
    • 151. Reverse Words in a String: The non-in-place version of this problem, often solved by splitting, reversing an array of words, and joining. Understanding both the in-place and non-in-place versions highlights the importance of constraints.
    • 557. Reverse Words in a String III: Reverse characters in each word, but keep the original word order. This is essentially just the second step of the current solution.
    • 189. Rotate Array: Another excellent problem that can be solved using the three-reversal technique (reverse first k elements, reverse remaining N-k elements, then reverse the whole array). This reinforces the versatility of the reversal pattern.
  • Common mistakes people make with this pattern:

    • Off-by-one errors: Incorrectly setting left, right, start, or end pointers, especially when dealing with loop conditions (< vs. <=) or calculating the end index (i - 1).
    • Incorrectly handling spaces: Forgetting to skip spaces, or misidentifying word boundaries, leading to partial word reversals or reversing spaces. This problem's constraints simplify this, but it's a common pitfall in variations.
    • Not modifying in-place: Accidentally creating new string or array copies, which violates the O(1) space complexity requirement.
    • Forgetting one of the reversal steps: Only reversing the whole array but not individual words, or vice-versa.
  • Variations of this problem exist:

    • Allowing multiple spaces between words (e.g., " hello world ").
    • Allowing leading or trailing spaces.
    • Reversing words in a string that contains punctuation, and deciding how to handle it (e.g., "hello, world!" -> "world! hello,").
    • Reversing only a specific subset of words or a range within the string.

6. Code Quality

The code quality is good:

  • Variable Naming: Variables like length, left, right, i, start, end are standard and descriptive within the context of two-pointer algorithms.
  • Code Structure: The two main steps of the algorithm are clearly separated by comments, which greatly enhances readability and understanding.
  • Readability: The use of array destructuring [s[left], s[right]] = [s[right], s[left]]; for swapping elements is modern JavaScript and very clear.
  • TypeScript Best Practices:
    • Correct use of const for length and let for mutable pointers.
    • No var is used.

Minor Improvement Suggestion:
For better modularity and to avoid code repetition (even if minimal), the core reverse logic could be extracted into a small helper function. This isn't strictly necessary here as the repeated block is small, but it's a good practice for more complex scenarios or if the reversal logic were to change.

function reverse(arr: string[], left: number, right: number): void {
  while (left < right) {
    [arr[left], arr[right]] = [arr[right], arr[left]];
    left++;
    right--;
  }
}

export function reverseWords(s: string[]): void {
  const length = s.length;
  if (length === 0) return;

  // Step 1: Reverse the entire array
  reverse(s, 0, length - 1);

  // Step 2: Reverse each individual word
  let i = 0;
  while (i < length) {
    // Skip leading spaces of a word (or between words)
    while (i < length && s[i] === ' ') {
      i++;
    }

    let start = i; // Start of the current word

    // Find the end of the current word
    while (i < length && s[i] !== ' ') {
      i++;
    }

    let end = i - 1; // End of the current word

    // Reverse the characters within the identified word
    // Only call reverse if a valid word was found (i.e., start < length)
    // The `start < end` check inside the reverse function handles single-character words or empty segments correctly.
    if (start < length) {
      reverse(s, start, end);
    }
  }
}

Self-correction: The if (start < length) check before calling reverse(s, start, end) is technically not strictly needed here because if start reaches length, then end would be length - 1, making start < end false, so the reverse function wouldn't perform any swaps anyway. However, it adds a layer of explicit clarity, especially if the reverse helper had side effects or more complex logic. For this problem, the original code's implicit handling is fine.

7. Alternative Approaches

  1. Using built-in string methods (if O(1) space is NOT required):

    • Convert the character array to a string: s.join('').
    • Split the string by spaces: str.split(' '). This creates an array of words.
    • Reverse the array of words: words.reverse().
    • Join the words back with spaces: words.join(' ').
    • Convert the final string back to a character array: result.split('').
    • Trade-offs: This approach is significantly simpler and quicker to implement. However, it violates the O(1) space constraint because it creates several intermediate strings and arrays (the joined string, the array of words, the final joined string), each potentially taking O(N) space.
  2. Two-pass approach with a temporary list of words (if O(1) space is NOT required for intermediate storage):

    • First pass: Iterate through the input character array, identify each word, and collect these words into a temporary string[] or char[][] array.
    • Second pass: Reverse this temporary list of words. Then, iterate through the reversed list, placing the characters back into the original input s array, ensuring to add single spaces between words.
    • Trade-offs: This approach is more intuitive than the three-reversal trick for some, as it directly manipulates words. However, it still uses O(N) auxiliary space to store the list of words, making it less optimal than the current solution for the given constraints.

The current solution is the most efficient and canonical approach for this problem when strict in-place and O(1) space requirements are present.

@pertrai1

Copy link
Copy Markdown
Owner Author

💡 Educational Note: Three-Loop Word Boundary Detection

while (i < length) {
  while (i < length && s[i] === ' ') { i++; }      // Skip spaces
  let start = i;
  while (i < length && s[i] !== ' ') { i++; }      // Find word end
  let end = i - 1;
  while (start < end) { /* reverse word */ }       // Reverse the word
}

This three-nested-loop structure is a common pattern for processing words in a character array:

  1. Outer loop (line 19): Scan through the entire array
  2. First inner loop (line 20): Skip any leading spaces
  3. Second inner loop (line 26): Find where the current word ends
  4. Third inner loop (line 32): Reverse the word using two-pointer swap

Time Complexity: Despite having nested loops, this is O(n) because each character is visited at most twice:

  • Once to find word boundaries (loops 1-2)
  • Once to reverse within the word (loop 3)

Common mistake: Setting start = 0 instead of start = i (line 24) would always reverse from the beginning of the array, not from the word's actual start position. This was debugged during the session!

@pertrai1

Copy link
Copy Markdown
Owner Author

🎯 How This Solution Works

Imagine you have a sentence written on index cards (one character per card), and you need to reverse the word order. How would you do it?

The Naive Approach (What You Might Try First):
Find each word, copy it to a temporary location, then rearrange. But that requires extra space!

The Clever Trick (What This Solution Does):
Think of it like shuffling a deck of cards in two steps:

Step 1: Flip the Entire Deck

First, we reverse the entire array from start to finish. This is like flipping the whole deck upside down.

Input:  ["t", "h", "e", " ", "s", "k", "y"]  // "the sky"
After:  ["y", "k", "s", " ", "e", "h", "t"]  // "yks eht" 

Notice something interesting? The words are now in the right order ("sky" comes before "the"), but each word's letters are backwards!

Step 2: Flip Each Word Back

Now we scan through and reverse each individual word. It's like un-flipping each card in the right position.

After:  ["s", "k", "y", " ", "t", "h", "e"]  // "sky the" ✅

Perfect! The words are in reversed order AND each word reads correctly.

Why This Works

The key insight: reversing the entire array puts words in the target order, but with characters flipped. Reversing each word individually then "un-flips" the characters without changing the word order.

It's like doing a double negative in math: flip everything, then flip each part back, and you end up with exactly what you want!

The Beauty of In-Place

The most elegant part? We never need extra space. We're just shuffling characters around using two pointers that meet in the middle — like two people walking toward each other in a hallway, swapping items as they pass.

Time: O(n) — We touch each character twice (once to reverse all, once to reverse words)
Space: O(1) — Just a few pointer variables, no extra arrays!

@pertrai1 pertrai1 merged commit 84de796 into main Feb 12, 2026
5 of 6 checks passed
@pertrai1 pertrai1 deleted the tdd/0186-reverse-words-in-a-string-ii branch February 12, 2026 14:42
@github-actions

Copy link
Copy Markdown

📅 Spaced Repetition Reviews Scheduled!

Great job solving #186 - Reverse Words In A String Ii! 🎉

To help you retain this knowledge long-term, I've scheduled 5 review sessions using spaced repetition:

Review Interval Schedule Logic
1st Review 1 day after solving Scheduled now
2nd Review 3 days after 1st review Auto-scheduled when 1st completes
3rd Review 7 days after 2nd review Auto-scheduled when 2nd completes
4th Review 14 days after 3rd review Auto-scheduled when 3rd completes
5th Review 30 days after 4th review Auto-scheduled when 4th completes

What to expect:

  • Your 1st review is scheduled for tomorrow
  • Each subsequent review is scheduled automatically when you complete the previous one
  • This ensures proper spacing even if you complete a review a few days late
  • GitHub issues will be created automatically for each review
  • Each issue will link back to your solution

🧠 Why Spaced Repetition?

Research shows that reviewing material at increasing intervals dramatically improves retention. This adaptive scheduling ensures optimal spacing based on when you actually complete each review!

Check docs/reviews/review-schedule.json to see your review schedule.

github-actions Bot pushed a commit that referenced this pull request Feb 12, 2026
  Problem: #186 - Reverse Words In A String Ii
  PR: #235
  First review scheduled (subsequent reviews auto-scheduled on completion)

  [skip ci]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code challenge this is a coding challenge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant