Problem 345

Abstract / Summary

Reverse the vowels in a given string while keeping other characters in their original positions.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 0345.py

class Solution:
    def reverseVowels(self, s: str) -> str:
        vowels = { "a", "e", "i", "o", "u", "A", "E", "I", "O", "U" }
        v = []
        for c in s:
            if c in vowels:
                v.append(c)

        result = ""
        for c in s:
            if c in vowels:
                result = result + v.pop()
            else:
                result = result + c

        return result
16 lines | 425 bytes | submitted August 13, 2023 | GitHub   tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 62% (2+ million submissions).

Typical patterns to solve this problem:
  • String
  • Two Pointers
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided Solution class implements a method reverseVowels that receives a string s and returns a new string where the vowels in s appear in reverse order while all non-vowel characters retain their original positions. The algorithm proceeds in two linear passes: the first extracts all vowels, the second rebuilds the output by substituting each vowel with the next one from the reversed collection.

Key Steps

Collecting Vowels

The method begins by defining a set containing both lowercase and uppercase vowel characters. Using a set enables constant-time membership checks. It then iterates over each character in the input string, appending any character that belongs to the vowel set to a list v. This list preserves the order of appearance of vowels, which will later be reversed by popping from the end.

vowels = { "a", "e", "i", "o", "u", "A", "E", "I", "O", "U" }
v = []
for c in s:
    if c in vowels:
        v.append(c)

Reconstructing Result

After gathering all vowels, the method constructs the final string. It initializes an empty string result and walks through the original string again. For each character, it checks whether the character is a vowel. If it is, the method appends the last element of v (obtained via pop()) to result, thereby inserting vowels in reverse order. If the character is not a vowel, it is appended unchanged.

result = ""
for c in s:
    if c in vowels:
        result = result + v.pop()
    else:
        result = result + c
return result

Edge Cases Handled

The algorithm gracefully handles an empty input string because the initial loops simply do not execute and the method returns an empty string. When the input contains no vowels, the list v remains empty; the second loop never attempts to pop from it because the vowel check fails for every character, resulting in the original string being returned unchanged. Strings composed exclusively of vowels are also correctly processed: the first loop collects all characters, and the second loop replaces each with the next vowel from the end of the list, effectively reversing the entire string. Mixed-case vowels are treated uniformly because the vowel set includes both cases, ensuring that uppercase vowels are recognized and reversed alongside lowercase ones. Consecutive vowel sequences are reversed as a block, preserving the relative order of surrounding consonants.

Performance Optimizations

A notable optimization is the use of a hash set for vowel membership testing. Set lookups execute in constant time, which is faster than scanning a list or string for each character. The collection of vowels into a list serves as a stack; using pop() removes the last element in constant time, providing an efficient way to retrieve vowels in reverse order without additional indexing arithmetic. By separating the extraction and reconstruction phases, the method avoids repeated scanning of the input for both vowel identification and placement, ensuring that each character is examined only twice. The algorithm also avoids auxiliary data structures beyond the minimal list for vowels and the result string, keeping memory usage tight while still achieving the desired reversal behavior.

written by openai gpt

ELI5 - Simplified Explanation

Imagine that every word or phrase is like a little train made of letters. Some of those letters are special, and they are called vowels. This code looks at all the letters in a string and picks out just those special vowels to put into a private box. After gathering all the vowels in the box, the code looks at the original string again from the very beginning. When it finds a regular letter that is not a vowel, it keeps the letter exactly where it is. When it finds one of the special vowels, it takes the very last vowel out of the box and uses that instead. Since the box gives back the vowels in reverse order, the vowels at the end of the line end up swapping places with the vowels at the start. Eventually, all the vowels end up in different spots than where they started, creating a new string where the vowels are backwards.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 27 | median = 7 | μ = 6.74 | σ = 0.89

Complexity Analysis

not analyzed yet

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Rust Go TS
LeetcodeHelp C++ Python Java
MemoryLimitExceeded C++ Python
Progiez C++ Python Java
github BigEggStudy C#
black-shadows C++
charles-wangkai Java
DimitrisJim C
everthis JS
fartem Ruby
halfrost Go
haoel C++
JoshCrozier JS
keineahnung2345 C++
Krazune C++
linouk23 C++
lkwq007 Python
lzl124631x C++
qiyuangong Python
ruoru Rust
shreymehul C#
suxrobGM C#
varunu28 Java
vli02 C
vthwang Java
XiaotaoGuo C++
YuriSpiridonov Python
zfang399 C++
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python, Rust, TypeScript
LeetcodeHelp C++, Java, Python
MemoryLimitExceeded Python, C++
Progiez C++, Java, Python
BigEggStudy C#
black-shadows C++, C++
charles-wangkai Java
DimitrisJim C
everthis JavaScript
fartem Ruby
halfrost Go
haoel C++
JoshCrozier JavaScript
keineahnung2345 C++
Krazune C++
linouk23 C++
lkwq007 Python
lzl124631x C++
qiyuangong Python
ruoru Rust
shreymehul C#
suxrobGM C#
varunu28 Java
vli02 C
vthwang Java
XiaotaoGuo C++
YuriSpiridonov Python
zfang399 C++
45 links | 30 authors | 10 languages

Videos

5 videos   did my crawler come up with invalid videos ? drop me a line.

Similar Problems

2 similar problems

Solved On The Same Day

12 easy
13 solutions   August 13, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality