Start learning free

LESSON 247 OF 677 · HELPER FUNCTIONS

Palindrome Words in Kotlin: A Two-Ended Helper

Practice Read the full explanation

You get an array of words, words. Return the words that are palindromes, in the same order.

A palindrome reads the same from left to right and from right to left, like "noon". A word with one letter is a palindrome too. If no word is a palindrome, the result is empty.

The work is split between two functions. The first one is a helper. It gets one word and returns true if it is a palindrome, false if not. The second one is the function that is graded. It keeps the words for which the helper returns true.

The helper compares the letters from both ends of the word, in one loop. Don't use a built-in function that reverses the word.

 

Example 1:

Input: words = ["pup", "cat", "noon", "dog"]
Output: ["pup", "noon"]
Explanation: The words "pup" and "noon" read the same both ways.
Read backwards, "cat" is "tac".
Read backwards, "dog" is "god".

Example 2:

Input: words = ["a", "bob", "abba", "ab"]
Output: ["a", "bob", "abba"]
Explanation: The word "a" has one letter, so it is a palindrome.
Read backwards, "ab" is "ba".

Example 3:

Input: words = ["kitten", "parrot"]
Output: []
Explanation: No word reads the same both ways.

 

Constraints:

  • words has at least one word.
  • Every word has 1 to 20 lowercase letters.
  • A word can appear more than once. Each palindrome is kept every time it appears.
STEP 1 OF 8
    Ctrl + Enter to check

    KOTLIN · HELPER FUNCTIONS

    Palindrome Words in Kotlin, explained

    Problem overview

    The function palindromeWords gets an array of words and returns the ones that are palindromes, in the same order. A palindrome reads the same from left to right and from right to left, like "noon". A one-letter word is a palindrome. A word that appears twice and is a palindrome is kept both times. If no word is a palindrome, the result is empty. Every word has 1 to 20 lowercase letters.

    For ["pup", "cat", "noon", "dog"] the answer is ["pup", "noon"]. For ["a", "bob", "abba", "ab"] it is ["a", "bob", "abba"], and for ["kitten", "parrot"] it is empty.

    The work is split in two. The helper isPalindrome gets one word and returns true or false. palindromeWords is the function the tests call, and it keeps the words for which the helper says true. The helper compares letters from both ends in one loop, without a built-in function that reverses the word.

    Approach for the helper

    Compare the first letter with the last, the second with the second to last, and so on. The word is a palindrome if every pair matches. You only need to check half of the word: after that, the pairs repeat. For a word of length n, the pair of index i is index n - 1 - i. For "noon", n is 4, so the pairs are index 0 with 3 and index 1 with 2. The loop is for (i in 0 until n / 2).

    The integer division n / 2 drops the remainder. For a word with 5 letters it is 2, so the middle letter is never compared, which is right: it is its own partner. For a one-letter word, n / 2 is 0, the loop never runs, and the word counts as a palindrome.

    Step by step

    1. In isPalindrome, store word.length in a val n.
    2. Loop i over 0 until n / 2. The range 0 until k goes from 0 to k - 1.
    3. If word[i] differs from word[n - 1 - i], return false at once. One bad pair is enough.
    4. After the loop, return true: no pair was different.
    5. In palindromeWords, create an empty mutableListOf<String>() named palindromes.
    6. Loop over words. If isPalindrome(word), add the word to the list. The call is already a Boolean, so it goes straight into the if.
    7. Return palindromes after the loop.

    The solution in Kotlin

    class Solution {
        fun isPalindrome(word: String): Boolean {
            val n = word.length
            for (i in 0 until n / 2) {
                if (word[i] != word[n - 1 - i]) {
                    return false
                }
            }
            return true
        }
    
        fun palindromeWords(words: Array<String>): List<String> {
            val palindromes = mutableListOf<String>()
            for (word in words) {
                if (isPalindrome(word)) {
                    palindromes.add(word)
                }
            }
            return palindromes
        }
    }
    

    In Kotlin, word[i] gives the Char at index i, and != compares the two characters by value. The helper gives true for "noon", "a" and "level", and false for "cat". The tests print lists as values separated by spaces, so the examples print:

    pup noon
    a bob abba
    

    The third example has no palindromes, so nothing is printed.

    Following the helper

    Here are the comparisons the helper makes for a few words. For "noon" it compares n with n and then o with o, and returns true. For "level" it compares l with l and e with e; the middle v is never compared, and the result is true. For "abca" it compares a with a, which matches, and then b with c, which does not, so it returns false before looking at anything else. For "a" there are no comparisons and the result is true.

    Because the helper stops at the first mismatch, it often does far less than the full half of the word.

    Kotlin details

    A few things in this code are specific to Kotlin:

    • 0 until n / 2 is a range that stops before n / 2. With n = 4 the values of i are 0 and 1. The range 0..n / 2 would include the end, which is one pair too many for even lengths.
    • The input type is Array<String>, and for (word in words) loops over it directly.
    • The result is built in a MutableList held in a val. The variable always points to the same list, and the list grows.
    • Comparing word[i] with word[n - 1 - i] compares two Char values, so != checks their contents.

    Complexity

    For a word of length n the helper makes at most n / 2 comparisons. palindromeWords calls it once per word, so the total work is proportional to the combined length of all the words. The result list holds at most as many words as the input.

    Common mistakes

    • Returning true on the first matching pair. Reversing the condition so it returns true when two letters are equal makes "abca" a palindrome, which it is not. The rule is to return false on the first mismatch, and true only after all the pairs.
    • Using n / 2 wrongly. Looping to n - 1 instead of stopping at the half compares the pairs again from the other side; it still gives the right answer for this task, but every pair is compared twice.
    • Off-by-one in the partner index. The partner of index i is n - 1 - i, not n - i, which goes past the end of the word and throws a StringIndexOutOfBoundsException.
    • Dropping duplicates. The words are visited in order and each is tested alone, so a palindrome that appears twice is kept twice.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free