Start learning free

LESSON 253 OF 415 · TWO POINTERS

Reverse Words in Swift: Two Pointers and an In-Place Reverse

Practice O(n) Read the full explanation

Given a string input, reverse the order of the words.

A word is defined as a sequence of non-space characters. The words in input 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

    SWIFT · TWO POINTERS

    Reverse Words in Swift, explained

    Problem overview

    The method reverseWords receives a string, input, made of words separated by a single space. It returns a string with the same words in reverse order, still separated by single spaces. A word is any run of non-space characters, and each word keeps its own spelling.

    For "sky is blue" the answer is "blue is sky". The order of the three words flips, but blue is still spelled blue, not eulb.

    Approach: reverse everything, then reverse each word

    You could split the string into words, reverse that list and join it again. This lesson uses a different idea that works on the characters themselves, with only two-pointer swaps.

    Take the whole string and reverse it. The words land in the opposite order, which is what we want, but each word is now spelled backwards:

    sky is blue   becomes   eulb si yks

    Reversing each word on its own puts its letters back in the right order. eulb turns into blue, si into is and yks into sky, and the spaces stay where they are. Two reversals of the same stretch of characters cancel each other, and that is why the trick works.

    Reversing a range uses two indices that start at its ends and move toward each other, swapping the characters they point at until they meet.

    Step by step

    1. Copy the characters into an array. A Swift String can't be indexed with an integer, so the code makes arr with Array(input). It is a var because the algorithm changes it.
    2. Reverse the whole array with a helper called reverse, from index 0 to arr.count - 1. The array is passed with & because the helper modifies it.
    3. Keep a start index i for the current word, and loop while i is inside the array.
    4. Find the end of the word. A second index j starts at i and moves right while it is inside the array and arr[j] isn't a space. The bounds check comes first, so arr[j] is never read past the end.
    5. Reverse the word. When the inner loop stops, the word occupies i to j - 1. Reversing that range fixes its spelling.
    6. Jump to the next word by setting i to j + 1, which skips the space.
    7. Convert back with String(arr) and return it.
    8. Write reverse. It takes the array as inout plus the two indices and swaps while i < j, moving i up and j down after each swap.
    9. Write swap. It saves arr[i] in temp, copies arr[j] into arr[i], then puts temp in arr[j].

    The solution in Swift

    class Solution {
        func swap(_ arr: inout [Character], _ i: Int, _ j: Int) {
            let temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp
        }
    
        func reverse(_ arr: inout [Character], _ i: Int, _ j: Int) {
            var i = i
            var j = j
            while i < j {
                self.swap(&arr, i, j)
                i += 1
                j -= 1
            }
        }
    
        func reverseWords(_ input: String) -> String {
            var arr = Array(input)
            self.reverse(&arr, 0, arr.count - 1)
            var i = 0
            while i < arr.count {
                var j = i
                while j < arr.count && arr[j] != " " {
                    j += 1
                }
                self.reverse(&arr, i, j - 1)
                i = j + 1
            }
            return String(arr)
        }
    }
    

    Swift details worth knowing:

    • inout parameters. Function parameters are constants, so a plain array parameter couldn't be modified. Marking it inout lets the helper change the caller's array, and the caller must pass it as &arr.
    • Shadowing i and j. Those parameters are constants too, so var i = i creates a mutable local copy with the same name. The caller's variables are not affected.
    • self.swap. Swift's standard library already has a global function called swap. Writing self.swap makes it clear that the class's own method is meant.
    • Characters, not bytes. Array(input) gives a [Character], and each Character is one user-visible character. A letter followed by a combining accent counts as one element, so reversing the array never separates an accent from its letter. For example, "cafe\u{301} au lait" becomes "lait au café", with the accent still on the e.
    • No ++. Swift has no increment operator, so the code uses += 1 and -= 1.

    Complexity

    Time: O(n). The full reversal touches each character once. The word loop moves j over every character once in total, and reversing the words touches each character at most once more. The work is a small constant times n.

    Space: O(n). The array of characters is a copy of the input, and String(arr) builds a result of the same size. The swaps themselves use a single extra variable. If the string were already a mutable array of characters, the algorithm would need O(1) extra space.

    Edge cases and common mistakes

    • Empty string. The array is empty, so the first call is reverse(&arr, 0, -1). The loop condition 0 < -1 is false, nothing happens, and the result is "".
    • One word. "single" is reversed twice and comes back unchanged.
    • The last word. It isn't followed by a space, so j stops at arr.count. The bounds check in the inner loop is what prevents a crash there.
    • Forgetting the second pass. Reversing only the whole string gives eulb si yks.
    • Off-by-one in the word range. Reversing i to j instead of i to j - 1 would drag the following space into the word.
    • Extra spaces. The lesson promises single spaces. With a doubled space, the code still runs and keeps the empty gap, so "a b" gives "b a", but leading or trailing spaces stay where reversal puts them: " a b" becomes "b a ".

    Testing

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