Typescript Coding Chronicles: Reverse Vowels of a String
Tags: webdev, javascript, programming, typescript
Published: 2024-07-10 20:12:09

## Problem Statement:
Given a string `s`, reverse only all the vowels in the string and return it.

The vowels are 'a', 'e', 'i', 'o', and 'u', and they can appear in both lower and upper cases, more than once.

### Example 1:
- Input: `s = "hello"`
- Output: `"holle"`

### Example 2:
- Input: `s = "leetcode"`
- Output: `"leotcede"`

### Constraints:
- `1 <= s.length <= 3 * 10^5`
- `s` consists of printable ASCII characters.

## Initial Thought Process:
To solve this problem, we need to identify all the vowels in the string, reverse their order, and then place them back in their original positions. This can be done using two approaches:
1. Brute Force Approach: Extract vowels, reverse them, and replace them in the string.
2. Two-Pointer Approach: Use two pointers to reverse vowels in place.

## Basic Solution:
### Code:
```typescript
function reverseVowelsBruteForce(s: string): string {
    const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
    let vowelList: string[] = [];

    // Extract vowels from the string
    for (let char of s) {
        if (vowels.has(char)) {
            vowelList.push(char);
        }
    }

    // Reverse the list of vowels
    vowelList.reverse();

    // Create a result array to build the output string
    let result: string[] = [];
    let vowelIndex = 0;

    // Reconstruct the string with reversed vowels
    for (let char of s) {
        if (vowels.has(char)) {
            result.push(vowelList[vowelIndex]);
            vowelIndex++;
        } else {
            result.push(char);
        }
    }

    return result.join('');
}
```

### Time Complexity Analysis:
- **Time Complexity:** O(n), where n is the length of the string. Extracting vowels, reversing them, and reconstructing the string each take O(n) time.
- **Space Complexity:** O(n), for storing the vowels and the result array.

### Limitations:
The brute force solution works well but uses additional space for storing vowels and the result array.

## Optimized Solution:
### Code:
```typescript
function reverseVowelsOptimized(s: string): string {
    const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
    let sArray = s.split('');
    let left = 0;
    let right = sArray.length - 1;

    while (left < right) {
        while (left < right && !vowels.has(sArray[left])) {
            left++;
        }
        while (left < right && !vowels.has(sArray[right])) {
            right--;
        }

        if (left < right) {
            [sArray[left], sArray[right]] = [sArray[right], sArray[left]];
            left++;
            right--;
        }
    }

    return sArray.join('');
}
```

### Time Complexity Analysis:
- **Time Complexity:** O(n), where n is the length of the string. Each character is checked at most twice.
- **Space Complexity:** O(n), for the array representation of the string. The space complexity can be considered O(1) if we don't count the space used for the input and output strings.

### Improvements Over Basic Solution:
- The optimized solution uses a two-pointer approach to reverse the vowels in place, reducing the need for additional space.

## Edge Cases and Testing:
### Edge Cases:
1. The string contains no vowels.
2. The string contains only vowels.
3. The string has upper and lower case vowels.
4. The string length is at the minimum or maximum limit.

### Test Cases:
```typescript
console.log(reverseVowelsBruteForce("hello")); // "holle"
console.log(reverseVowelsBruteForce("leetcode")); // "leotcede"
console.log(reverseVowelsBruteForce("aA")); // "Aa"
console.log(reverseVowelsBruteForce("")); // ""
console.log(reverseVowelsBruteForce("bcdfg")); // "bcdfg"

console.log(reverseVowelsOptimized("hello")); // "holle"
console.log(reverseVowelsOptimized("leetcode")); // "leotcede"
console.log(reverseVowelsOptimized("aA")); // "Aa"
console.log(reverseVowelsOptimized("")); // ""
console.log(reverseVowelsOptimized("bcdfg")); // "bcdfg"
```

## General Problem-Solving Strategies:
1. **Understand the Problem:** Carefully read the problem statement and constraints to understand what is required.
2. **Identify Key Operations:** Determine the key operations needed, such as identifying and reversing vowels.
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 words in a sentence.

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

3. **Character-Based Operations:**
   - Problems where operations are performed based on specific characters or character sets.
   - Example: Checking if a string is a palindrome by ignoring non-alphanumeric characters.

## Conclusion:
- The problem of reversing vowels in a string can be efficiently solved using both a brute force approach and an optimized two-pointer 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.