Reverse Words in a String
Reverse word order while normalising whitespace, with a two-reversal in-place technique
Problem Statement
Given a string s, reverse the order of its words. A word is a maximal run of non-space characters.
The result must have words separated by a single space, with no leading or trailing spaces.
Input: "the sky is blue"
Output: "blue is sky the"
Input: " hello world "
Output: "world hello" (leading/trailing spaces removed)
Input: "a good example"
Output: "example good a" (multiple spaces collapsed)Two jobs in one problem
Reverse the word order — the headline task.
Normalise whitespace — trim the ends and collapse runs of spaces to one. Most wrong answers get the first part right and the second part wrong.
Intuition
The direct approach
Split on whitespace, reverse the resulting list, join with single spaces. Both languages' split functions can be made to drop empty pieces, which handles the normalisation for free.
This is O(n) time and O(n) space, and it is a perfectly good answer.
The in-place approach
The classic follow-up asks for O(1) extra space, which is possible in languages with mutable strings (C++, Java's char[]). It relies on a neat identity.
The key insight — reverse twice
- Reverse the entire string. Now the words are in the right order, but each word's letters are backwards.
- Reverse each word individually. The letters come out right, and the word order stays correct.
"the sky is blue"
→ reverse everything → "eulb si yks eht"
→ reverse each word → "blue is sky the"Reversing twice at different granularities cancels out at the character level while leaving the word-level reordering intact.
Python and TypeScript have immutable strings, so a true O(1) version is not achievable — but the technique is worth understanding, and it is what interviewers are probing for.
Watch it run
Approach
Split on runs of whitespace
Dropping empty pieces handles leading, trailing and repeated spaces in one step.
Solution
def reverse_words(s: str) -> str:
"""Reverse word order, collapsing whitespace to single spaces."""
# split() with no argument splits on runs of whitespace and drops empties.
words = s.split()
return " ".join(reversed(words))The manual version, which shows the whitespace handling explicitly:
def reverse_words_manual(s: str) -> str:
words: list[str] = []
i = len(s) - 1
while i >= 0:
# Skip spaces between words.
while i >= 0 and s[i] == " ":
i -= 1
if i < 0:
break
# Collect one word, scanning right to left.
end = i
while i >= 0 and s[i] != " ":
i -= 1
words.append(s[i + 1 : end + 1])
return " ".join(words)Scanning from the right collects words in reversed order directly, so no separate reversal is needed.
`split(' ')` is not the same as `split()`
Python: "a b".split(" ") gives ["a", "", "b"] — the empty string between the two spaces survives, and joining would produce a double space. "a b".split() with no argument gives ["a", "b"].
TypeScript: "a b".split(' ') has the same problem. Use .trim().split(/\s+/), which both removes the ends and collapses the middle.
Forgetting trim() before the regex split is also a bug: " a b".split(/\s+/) starts with an empty string.
Complexity Analysis
Time Complexity
O(n)
Space Complexity
O(n)
- Time — one pass to split, one to reverse, one to join.
- Space —
O(n)for the word list and the output. In a language with mutable strings, the double-reversal approach achievesO(1)extra space.
Edge Cases
Related Problems
- Length of Last Word — the same skip-then-collect whitespace scanning
- Reverse Linked List — reversal on a different structure
- Valid Palindrome — two-pointer string traversal