Reverse Words in a String is a classic string-manipulation warm-up. The twist that trips people up: you reverse the order of the words, not the characters — each word stays spelled the same, only their positions flip.
Problem. Given a string s, reverse the order of the words. A word is a sequence of
non-space characters. Return a single string with the words in reverse order, separated by a single
space.
Example: s = "code wins arguments" → answer "arguments wins code".
The slow way first
A tempting first move: scan the string character by character, find each word boundary by hand, push words onto a stack, then pop them off to build the answer. That works, but it is fiddly — you are manually tracking spaces, word starts, and word ends, and it is easy to mishandle leading, trailing, or doubled spaces.
The question to ask: can the language do the boring parts for me? Splitting on whitespace and joining with a space are one-liners in Python. Once the words are in a list, "reverse the words" becomes the much simpler "reverse a list."
The idea: split, reverse the list, join
Three clean phases:
- Split the string into a list of words. Python's
split()with no argument collapses any run of whitespace, so extra spaces vanish for free. - Reverse the list with two pointers:
loat the front,hiat the back. Swap the pair, then steploright andhileft. Stop when they meet. - Join the reversed list with a single space.
The two-pointer reverse is the reusable part: swapping the ends of a list and walking inward reverses any sequence in O(n) time using O(1) extra swaps.
Walk through it
Step through the animation. First the sentence splits into three word cells: ["code", "wins", "arguments"]. Then lo and hi start at the ends: they swap "code" and "arguments", then move inward and meet on "wins". Since lo is no longer left of hi, the loop stops — the middle word never had to move. The list now reads ["arguments", "wins", "code"], and join stitches it back into "arguments wins code".
Pseudocode
words = split s on whitespace # ["code", "wins", "arguments"]
lo = 0, hi = last index of words
while lo < hi:
swap words[lo] and words[hi] # exchange the two ends
lo = lo + 1 # step the front pointer right
hi = hi - 1 # step the back pointer left
return the words joined by single spacesThe Python solution
def reverse_words(s):
words = s.split()
lo, hi = 0, len(words) - 1
while lo < hi:
words[lo], words[hi] = words[hi], words[lo]
lo += 1
hi -= 1
return " ".join(words)s.split()with no argument splits on any whitespace and drops empty pieces, so leading, trailing, and repeated spaces are handled automatically.lo, hi = 0, len(words) - 1puts one pointer at each end of the word list.- The
while lo < hiloop runs only while the pointers have not met or crossed. - Line 5 is the swap — Python lets us exchange
words[lo]andwords[hi]in a single tuple assignment. lo += 1andhi -= 1march the pointers toward the middle so each pair is swapped exactly once." ".join(words)glues the reversed list back into a string with one space between words.
Complexity
| Case | Time | Notes |
|---|---|---|
| Split the string | O(n) (moderate) | scan every character once |
| Two-pointer reverse | O(w) (moderate) | w = number of words, w/2 swaps |
| Join the words | O(n) (moderate) | build the output string |
O(n) (moderate)Everything is linear in the length of the string, so the whole thing is O(n) time. We use O(n) extra space for the list of words and the output string.
When this pattern shows up
Whenever you need to reverse a sequence in place — a list, an array, the characters of a string — reach for the two-pointer swap: one pointer at each end, swap, then walk both inward until they meet. It is O(n) time with no extra array.
Watch the input edge cases. Real inputs often have leading, trailing, or multiple spaces between
words. Pythons bare split() collapses them all, but if you split on a literal single space you will get
stray empty strings — and your join will produce double spaces.
Practice
For words = ['code', 'wins', 'arguments'], after the first swap (lo = 0, hi = 2), what does the list look like and where do the pointers move next?
1. What does this problem ask you to reverse?
2. Why does the while loop condition use lo < hi rather than lo <= hi?
3. Why prefer bare split() over splitting on a single space?
4. What is the time complexity of the full solution?