Start learning free

LESSON 248 OF 678 · HELPER FUNCTIONS

Palindrome Words in Swift: Comparing Letters From Both Ends

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 9
    Ctrl + Enter to check

    SWIFT · HELPER FUNCTIONS

    Palindrome Words in Swift, explained

    Problem overview

    The function palindromeWords receives 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. If a palindrome appears twice in the input it is kept twice, and if none is a palindrome the result is empty. Built-in functions that reverse a word are off limits.

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

    Approach: a helper for one word

    The lesson splits the job in two. The helper isPalindrome answers the question for a single word, and palindromeWords keeps the words for which the answer is true.

    To test one word, compare its first letter with its last, its second with the second to last, and so on. If any pair differs, the word is not a palindrome. Only half the word needs checking, because the second half repeats the same pairs. In a five-letter word the middle letter has no partner and needs no check.

    Step by step

    1. Turn the word into an array of letters: let letters = Array(word). A Swift string can't be read with a number index, but an array of its characters can.
    2. Store the count in let n = letters.count.
    3. Loop over the first half: for i in 0..<n / 2. Integer division drops the remainder, so 5 letters give 2 pairs and 4 letters give 2 pairs.
    4. Compare the pair. The partner of letters[i] is letters[n - 1 - i]. For i = 0 it is the last letter. If they differ, return false at once, since one different pair settles it.
    5. Return true after the loop. A one-letter word skips the loop (0 pairs) and also gets here.
    6. In palindromeWords, start with an empty [String] named palindromes, declared with var.
    7. Loop over the words from first to last, so the order is kept.
    8. Append the word when isPalindrome(word) is true. The call is already a Bool, so it goes straight into the if.
    9. Return palindromes.

    The solution in Swift

    class Solution {
        func isPalindrome(_ word: String) -> Bool {
            let letters = Array(word)
            let n = letters.count
            for i in 0..<n / 2 {
                if letters[i] != letters[n - 1 - i] {
                    return false
                }
            }
            return true
        }
    
        func palindromeWords(_ words: [String]) -> [String] {
            var palindromes = [String]()
            for word in words {
                if isPalindrome(word) {
                    palindromes.append(word)
                }
            }
            return palindromes
        }
    }
    

    Swift details: Array(word) gives an [Character], and two Character values compare with !=. In 0..<n / 2, the division happens before the range is formed, so the range is 0..<(n / 2). A range like 0..<0 is empty and the loop body never runs, which is what makes the one-letter case work.

    Tracing the pairs

    For "noon", n is 4 and the loop runs for i equal to 0 and 1. Index 0 pairs with index 3 (both n), and index 1 pairs with index 2 (both o). Every pair matches, so the helper returns true.

    For "abca" the pair at indexes 0 and 3 matches (a and a), but the pair at indexes 1 and 2 is b and c. The helper returns false there, without looking further.

    Why a helper is worth it

    The pair-comparing loop is the hard part, and it lives in one place. palindromeWords is a plain filter: loop, ask, keep. You can try the helper alone on single words before trusting it inside the loop, and the second function never needs to know how the check works.

    The three examples give:

    ["pup", "noon"]
    ["a", "bob", "abba"]
    []
    

    Single checks: isPalindrome("a") is true, isPalindrome("ab") is false, isPalindrome("abc") is false and isPalindrome("abca") is false. The last one has matching ends but different middle letters, so it shows why every pair must be checked.

    Another way, once built-ins are allowed

    The lesson asks for the pair-comparing loop, but in a program of your own a palindrome test can also be written as word == String(word.reversed()), which builds the reversed word and compares the two. The filtering function can pass the helper straight to filter: words.filter { isPalindrome($0) } returns ["pup", "noon"] for the first example. Both forms give the same answers as the loops above. The loops show what is happening, and the pair comparison builds no second string.

    Case and letters

    The lesson's words are all lowercase, so no case handling is needed. In general, Swift compares characters exactly: isPalindrome("Noon") is false, because the capital N and the lowercase n are different characters, while isPalindrome("noon") is true.

    Words that repeat

    The constraints allow the same word to appear more than once. The loop treats every position separately, so ["noon", "noon"] returns both copies. The function does not remove repeats.

    Common mistakes

    • Looping over the whole word. It still gives the right answer, since the second half repeats the pairs, but it does twice the work.
    • Returning true inside the loop after one matching pair. One match proves nothing. Only a different pair is conclusive.
    • Using n - i as the partner index. The last index is n - 1, so n - i runs off the end of the array and crashes the program.
    • Indexing the string directly. word[0] does not compile in Swift, hence Array(word).
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free