A CMS paste dumps a headline with double spaces and a trailing blank. Product wants the words last-first for a preview: "the sky is blue" becomes "blue is sky the", and " hello world " must become "world hello" — one space, no padding. The intern split on every ' ' and joined the pieces back. Staging titles with single spaces looked fine. Production pastes like "a good example" came back with holes between the tokens.

Reverse Words in a String asks you to reverse word order, collapse runs of spaces, and trim the ends. A word is a maximal run of non-space characters. Java String is immutable, so every answer allocates a result.

This is an interview writeup, not a two-pointers lecture. The two pointers post owns the left/right swap. Here we only care about which slice you reverse: the compacted buffer first, then each word so the letters face forward again.

The problem

Given a String s, return its words in reverse order, joined by a single space. Drop leading, trailing, and repeated spaces. There is at least one word.

s = "the sky is blue"     →  "blue is sky the"
s = "  hello world  "     →  "world hello"
s = "a good   example"    →  "example good a"

Note: This reverses word order, not the letters inside a word. Reverse Words III keeps sentence order and flips characters inside each token. Different prompt; do not recycle that proof.

Split, reverse, join is the honest brute force

Split on spaces, drop empty tokens, reverse the list, join with one space. Correct. Extra linear space for the words. Interviewers often accept it; in Java it is the practical answer.

String reverseWordsSplit(String s) {
    List<String> words = new ArrayList<>();
    for (String w : s.split(" ")) {
        if (!w.isEmpty()) {
            words.add(w);
        }
    }
    Collections.reverse(words);
    return String.join(" ", words);
}

At a tweet this is a rounding error. At a buffer they asked you not to tokenise, you paid a list of strings for a question two reverses answer on a char[]: compact the spaces, reverse the whole sentence, then reverse each word.

s.trim().split("\\s+") is the same idea with a regex. Say you know split(" ") leaves "" between consecutive spaces — that is why the filter exists. Do not pretend split is in-place.

Reverse the buffer, then reverse each word

Copy to a char[]. Compact in place: skip extra spaces while writing, one space between words, no padding. Reverse [0, n). Reverse each word. new String(a, 0, n) is the result.

Walk " hello world ":

s = "  hello world  "

compact:
  skip leading spaces
  copy hello, one space, copy world
  a[0..10] = hello world     n=11

reverse whole [0..10]:
  dlrow olleh

reverse word [0..4]:  world olleh
reverse word [6..10]: world hello

The Java is that walk. reverse is the usual two-index swap. Compact writes a non-space, and inserts one space only when a word starts after another word:

String reverseWords(String s) {
    char[] a = s.toCharArray();
    int n = compact(a);
    reverse(a, 0, n - 1);
    int start = 0;
    for (int i = 0; i <= n; i++) {
        if (i == n || a[i] == ' ') {
            reverse(a, start, i - 1);
            start = i + 1;
        }
    }
    return new String(a, 0, n);
}

int compact(char[] a) {
    int w = 0;
    for (int i = 0; i < a.length; i++) {
        if (a[i] == ' ') {
            continue;
        }
        if (w > 0 && a[i - 1] == ' ') {
            a[w++] = ' ';
        }
        a[w++] = a[i];
    }
    return w;
}

void reverse(char[] a, int lo, int hi) {
    while (lo < hi) {
        char t = a[lo];
        a[lo] = a[hi];
        a[hi] = t;
        lo++;
        hi--;
    }
}

Time is O(n) — compact, reverse-all, and reverse-each-word each scan the buffer once. Space is O(n) in Java for the char[] and the result string. A mutable buffer follow-up can do the same dance with O(1) extra besides a handful of indexes.

Note: Do not skip compact and hope join will save you. Reverse-all on " hello world " leaves leading spaces at the other end. If compact forgets the w &gt; 0 guard, a leading word writes a space first and you ship a padded result.

What interviewers usually poke next

  • split("\\s+") without trim. In Java a leading delimiter yields a leading "". Filter empties, or trim first. Say it before they paste " hello world ".
  • Deque from the end. Scan backward, collect each word, join. Same O(n) extra, no reverse-twice. Honest if they do not want a char[].
  • Java immutability. O(1) extra space is a C++ / mutable-buffer follow-up. toCharArray plus new String already paid linear.
  • Reverse Words III. Sentence order stays; letters inside each token flip. This walk has no “keep order” branch; do not pretend it does.
  • Null. Production would reject. At the board, ask.

You are done with this problem when you can say, out loud, why split-filter-reverse-join is correct, why reverse-all then reverse-each restores the letters, and why compact has to happen or you ship extra spaces.