Start learning free

LESSON 229 OF 348 · TWO POINTERS

Reverse Words in Kotlin: Reverse the Whole String, Then Each Word

Practice O(n) Read the full explanation

Given an input string s, reverse the order of the words.

A word is defined as a sequence of non-space characters. The words in s will be separated by one space for simplicity.

Return a string of the words in reverse order concatenated by a single space.

Example:

Input:  input = "sky is blue"

Output:  "blue is sky"
STEP 1 OF 18
    Ctrl + Enter to check

    KOTLIN · TWO POINTERS

    Reverse Words in Kotlin, explained

    Problem overview

    The function reverseWords takes a String named input made of words separated by single spaces. It returns a string with the words in the opposite order, again separated by single spaces. A word is a run of characters that aren't spaces, and the letters inside each word keep their normal order.

    For "sky is blue" the result is "blue is sky".

    Approach: two rounds of reversing

    A quick way to reverse word order is to split the string at spaces, reverse the list and join it back. This lesson does it with arrays and pointers only, using a neat trick: reverse the entire string first, then reverse each word individually.

    Reversing everything puts the words in the right order, but it also spells each word backwards. Take "sky is blue":

    sky is blue
    eulb si yks
    blue is sky
    

    The second line is the whole string reversed: the words are in the target order, with their letters flipped. The third line comes from reversing each word on its own. The spaces stay at the same positions, because reversing a word never moves anything outside the word.

    Both rounds use the same operation, "reverse a range of an array in place", so the lesson writes it once as a helper, which in turn uses a small swap helper.

    The word loop on "eulb si yks" (11 characters) works like this. At i = 0, j stops at index 4, the first space, so the word is indices 0 to 3 and it becomes blue. Then i jumps to 5, where j stops at index 7, and si becomes is. Finally i is 8, j runs to 11, the array size, and yks becomes sky. Then i becomes 12 and the loop ends.

    Step by step

    1. Copy the string into a CharArray named arr with toCharArray(). Kotlin strings are immutable, so the work needs a mutable copy.
    2. Reverse everything with reverse(arr, 0, arr.size - 1). The helper is defined later.
    3. Create i, a var starting at 0. It marks the start of the current word.
    4. Loop while i < arr.size, one iteration per word.
    5. Create j equal to i. It will scan forward to the end of the word.
    6. Advance j while it is inside the array and arr[j] isn't a space. The check j < arr.size comes first so that arr[j] is never read past the end.
    7. Reverse the word. When the inner loop stops, the word spans i to j - 1, so call reverse(arr, i, j - 1).
    8. Jump to the next word with i = j + 1, skipping the space at j.
    9. Convert back with String(arr) and return it.
    10. Write reverse with the parameters arr, i and j. Copy i and j into var variables left and right, since parameters can't be reassigned.
    11. Loop while left < right, call swap(arr, left, right), then do left++ and right--.
    12. Write swap with a temporary: save arr[i] in temp, copy arr[j] into arr[i], and put temp into arr[j].

    The solution in Kotlin

    class Solution {
        fun swap(arr: CharArray, i: Int, j: Int) {
            val temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp
        }
    
        fun reverse(arr: CharArray, i: Int, j: Int) {
            var left = i
            var right = j
            while (left < right) {
                swap(arr, left, right)
                left++
                right--
            }
        }
    
        fun reverseWords(input: String): String {
            val arr = input.toCharArray()
            reverse(arr, 0, arr.size - 1)
            var i = 0
            while (i < arr.size) {
                var j = i
                while (j < arr.size && arr[j] != ' ') {
                    j++
                }
                reverse(arr, i, j - 1)
                i = j + 1
            }
            return String(arr)
        }
    }
    

    Kotlin details worth knowing:

    • A Char literal uses single quotes. ' ' is the space character, while " " would be a one-character String. Comparing a Char with a String using != doesn't compile.
    • Arrays are shared, not copied, when passed. reverse and swap change the array in place, and reverseWords sees the result. That's why they return nothing.
    • && short-circuits. When j equals arr.size, the right side isn't evaluated, so there is no out-of-bounds read.
    • Inclusive ranges. reverse treats both i and j as part of the range, which is why the whole array is 0 to arr.size - 1 and a word is i to j - 1.
    • String(arr) builds a new string from the array's characters, copying them.

    Complexity

    Time: O(n). The whole-string reversal touches each character once. The word loop moves j over every character once and each word's reversal touches each of its characters once, so the second round is also linear.

    Space: O(n). The character array is a copy of the input, and the final string is another. The reversing itself needs only a few integers and one temporary character.

    Edge cases and common mistakes

    • A single word. "hello" is reversed to "olleh" and then reversed back to "hello".
    • Empty string. The array is empty, reverse(arr, 0, -1) does nothing because left < right is false, the word loop doesn't run, and the result is "".
    • Last word. There is no space after it, so j stops at arr.size. Reversing i to j - 1 still covers it, and the final i = j + 1 ends the loop.
    • Extra spaces. The lesson promises single spaces. If there were more, the spaces would be reversed along with the rest: "a b" gives "b a", and a leading space moves to the end.
    • Reversing only the words. The words keep their order and just flip their letters. Reversing only the whole string gives backward words. Both rounds are needed.
    • Passing j instead of j - 1. That would include the space after the word, moving it to the front of the word.

    Testing

    • "sky is blue" gives "blue is sky".
    • "hello" gives "hello".
    • "a b" gives "b a".
    • "" gives "".
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free