Typescript Coding Chronicles: Reverse Words in a String
Tags: webdev, javascript, programming, typescript
Published: 2024-07-11 19:09:49

## Problem Statement:
Given an input string `s`, reverse the order of the words. A word is defined as a sequence of non-space characters. The words in `s` will be separated by at least one space. Return a string of the words in reverse order concatenated by a single space.

Note that `s` may contain leading or trailing spaces or multiple spaces between two words. The returned string should only have a single space separating the words. Do not include any extra spaces.

### Example 1:
- Input: `s = "the sky is blue"`
- Output: `"blue is sky the"`

### Example 2:
- Input: `s = "  hello world  "`
- Output: `"world hello"`
- Explanation: Your reversed string should not contain leading or trailing spaces.

### Example 3:
- Input: `s = "a good   example"`
- Output: `"example good a"`
- Explanation: You need to reduce multiple spaces between two words to a single space in the reversed string.

### Constraints:
- `1 <= s.length <= 10^4`
- `s` contains English letters (upper-case and lower-case), digits, and spaces ' '.
- There is at least one word in `s`.

## Initial Thought Process:
To solve this problem, we need to:
1. Split the string into words.
2. Reverse the order of the words.
3. Join the words back together with a single space between each.

## Basic Solution:
### Code:
```typescript
function reverseWordsBruteForce(s: string): string {
    // Split the string by spaces and filter out empty strings
    let words = s.trim().split(/\s+/);

    // Reverse the array of words
    words.reverse();

    // Join the words with a single space
    return words.join(' ');
}
```

### Time Complexity Analysis:
- **Time Complexity:** O(n), where n is the length of the string. Splitting, reversing, and joining all take linear time.
- **Space Complexity:** O(n), where n is the length of the string. We store the words in an array and the final result in a string.

### Limitations:
This solution is efficient given the constraints. However, it uses additional space for the array of words.

## Optimized Solution:
If the string data type is mutable and we need to solve it in-place with O(1) extra space, we can use a two-pointer technique to reverse the words within the original string.

### Code:
```typescript
function reverseWordsOptimized(s: string): string {
    // Trim the string and convert it to an array of characters
    let chars = s.trim().split('');

    // Helper function to reverse a portion of the array in place
    function reverse(arr: string[], left: number, right: number) {
        while (left < right) {
            [arr[left], arr[right]] = [arr[right], arr[left]];
            left++;
            right--;
        }
    }

    // Reverse the entire array of characters
    reverse(chars, 0, chars.length - 1);

    // Reverse each word in the reversed array
    let start = 0;
    for (let end = 0; end <= chars.length; end++) {
        if (end === chars.length || chars[end] === ' ') {
            reverse(chars, start, end - 1);
            start = end + 1;
        }
    }

    // Join the characters back into a string and split by spaces to remove extra spaces
    return chars.join('').split(/\s+/).join(' ');
}
```

### Time Complexity Analysis:
- **Time Complexity:** O(n), where n is the length of the string. Each character is processed a constant number of times.
- **Space Complexity:** O(1), as we are modifying the array in place and using only a constant amount of extra space.

### Improvements Over Basic Solution:
- The optimized solution reduces space complexity by performing in-place operations on the array of characters.

## Edge Cases and Testing:
### Edge Cases:
1. The string contains leading and trailing spaces.
2. The string contains multiple spaces between words.
3. The string contains only one word.
4. The string length is at the minimum or maximum limit.

### Test Cases:
```typescript
console.log(reverseWordsBruteForce("the sky is blue")); // "blue is sky the"
console.log(reverseWordsBruteForce("  hello world  ")); // "world hello"
console.log(reverseWordsBruteForce("a good   example")); // "example good a"
console.log(reverseWordsBruteForce("singleWord")); // "singleWord"
console.log(reverseWordsBruteForce("   ")); // ""

console.log(reverseWordsOptimized("the sky is blue")); // "blue is sky the"
console.log(reverseWordsOptimized("  hello world  ")); // "world hello"
console.log(reverseWordsOptimized("a good   example")); // "example good a"
console.log(reverseWordsOptimized("singleWord")); // "singleWord"
console.log(reverseWordsOptimized("   ")); // ""
```

## General Problem-Solving Strategies:
1. **Understand the Problem:** Carefully read the problem statement to understand the requirements and constraints.
2. **Identify Key Operations:** Determine the key operations needed, such as splitting, reversing, and joining words.
3. **Optimize for Readability:** Use clear and concise logic to ensure the code is easy to follow.
4. **Test Thoroughly:** Test the solution with various cases, including edge cases, to ensure correctness.

## Identifying Similar Problems:
1. **String Manipulation:**
   - Problems where you need to modify strings based on specific conditions.
   - Example: Reversing the order of characters in each word of a sentence.

2. **Two-Pointer Technique:**
   - Problems where using two pointers can help optimize the solution.
   - Example: Removing duplicates from a sorted array.

3. **In-Place Algorithms:**
   - Problems where operations need to be performed in place with limited extra space.
   - Example: Rotating an array to the right by k steps.

## Conclusion:
- The problem of reversing words in a string can be efficiently solved using both a brute force approach and an optimized in-place approach.
- Understanding the problem and breaking it down into manageable parts is crucial.
- Using clear logic and optimizing for readability ensures the solution is easy to follow.
- Testing with various edge cases ensures robustness.
- Recognizing patterns in problems can help apply similar solutions to other challenges.

By practicing such problems and strategies, you can improve your problem-solving skills and be better prepared for various coding challenges.