Start learning free

LESSON 226 OF 348 · TWO POINTERS

Reverse String in Kotlin: Swapping Characters with Two Pointers

Practice O(n) Read the full explanation

Given a string, write a function that reverses that string without using built-in functions or libraries.

Example:

Input:  "hello"

Output: "olleh"

Note:

Your algorithm should run in O(n) time and use O(n) extra space.


STEP 1 OF 9
    Ctrl + Enter to check

    KOTLIN · TWO POINTERS

    Reverse String in Kotlin, explained

    Problem overview

    The function reverse takes a String named input and returns a new string with the same characters in the opposite order. For "hello" the result is "olleh". The statement allows O(n) time and O(n) extra space.

    Approach: copy, then swap from both ends

    A Kotlin String can't be changed after it is created, so there is no way to swap two of its characters in place. The lesson therefore copies the characters into a CharArray, which is mutable, reverses the array, and builds a new string from it. The copy is the O(n) extra space the statement allows.

    Reversing the array uses two pointers. One starts at the first index and one at the last. Swapping the characters they point at puts each of them in its final place. Then both pointers move one step inward, and the process repeats until they meet or cross. Each swap fixes two positions, so about half as many swaps as characters are needed.

    On "hello" the pointers start at indices 0 and 4. The first swap exchanges h and o, giving oellh. Then indices 1 and 3 swap e and l, giving olleh. The pointers then meet at index 2, the middle character, which stays where it is.

    Kotlin's standard library already has reversed() for strings, so in everyday code you would call that. Writing the loop yourself teaches the two-pointer technique, which also reverses arrays and parts of arrays in place, a skill used in many other problems.

    Step by step

    1. Copy the characters into a val charArray with input.toCharArray(). The val only stops the variable from being reassigned; the elements can still change.
    2. Create left as a var set to 0.
    3. Create right as a var set to charArray.size - 1, the last index.
    4. Loop while left < right. Once the pointers meet or cross, every pair has been swapped. For an odd length, the middle character has no partner and stays.
    5. Call swap(charArray, left, right) in the loop. The helper is written next.
    6. Write swap above reverse. It takes the array and two indices. It needs no return type, because the array is shared with the caller, so the caller sees the change.
    7. Swap with a temporary. Save arr[i] in c, copy arr[j] into arr[i], then put c into arr[j]. Without the temporary, the first assignment would overwrite a value before it is saved.
    8. Move the pointers with left++ and right--.
    9. Build the result with String(charArray) and return it.

    The solution in Kotlin

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

    Kotlin details worth knowing:

    • Arrays are passed by reference. swap receives the same array object that reverse holds, not a copy. Writing arr[i] = arr[j] inside swap therefore changes the array the caller sees. That is why swap returns nothing, and its return type is the implicit Unit.
    • Parameters can't be reassigned. Inside swap, you can write to arr[i] but not to arr itself or to i. That is also why reverse uses its own var pointers.
    • toCharArray() copies. Changing charArray never affects input, so the caller's string is safe.
    • String(charArray) builds a new string from the array's characters. It also copies, so later changes to the array wouldn't show up in the string.
    • Characters are UTF-16 units. A symbol such as an emoji takes two units, called a surrogate pair. Reversing units swaps the two halves of the pair and produces a broken symbol. For plain letters, like in the lesson, this is not an issue.

    The same helper works on any part of an array. Calling swap with two indices exchanges exactly those two characters and touches nothing else, which is why the main loop can stay so short. Splitting the work into a small, testable helper and a loop that decides which pairs to swap is a habit worth keeping.

    Complexity

    Time: O(n). Copying the characters is linear, the loop runs about n / 2 times with constant work in each swap, and building the string is linear.

    Space: O(n). The CharArray holds n characters and the final string holds another n. The swaps themselves need only one temporary character.

    Edge cases and common mistakes

    • Empty string. right is -1, the loop never runs and the function returns "".
    • One character. Both pointers would be at index 0; the loop doesn't run, so "a" stays "a".
    • Odd and even lengths. "abc" becomes "cba", with the middle b untouched. An even length such as "abcd" ends with the pointers crossed.
    • Loop condition left <= right. It swaps the middle character with itself, which is harmless but unnecessary.
    • Swapping without a temporary. Writing arr[i] = arr[j] and then arr[j] = arr[i] leaves both positions holding the old arr[j].
    • Looping over the whole array. Running the pointers past the middle swaps every pair twice and restores the original order.

    Testing

    • "hello" gives "olleh".
    • "abc" gives "cba".
    • "abcd" gives "dcba".
    • "a" gives "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