Problem overview
You get a string[] named words. PalindromeWords returns the words that read the same from left to right and from right to left, in the same order, as a List<string>. A word with one letter counts as a palindrome. If no word qualifies, the result is an empty list.
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. A word that appears twice is kept each time.
Approach
The work is split in two. The helper IsPalindrome answers the question for one word. PalindromeWords loops over the array and keeps the words for which the helper says true.
The helper compares letters in pairs from both ends: the first with the last, the second with the second to last, and so on. One pair that differs settles it: the word is not a palindrome. If every pair matches, it is. Only half of the word needs to be checked, because the second half is the same pairs seen from the other side. The middle letter of an odd-length word has no partner and needs no check.
Step by step
- In
IsPalindrome, storeword.Lengthinn. Both the loop limit and the partner's index use it. - Loop with
for (int i = 0; i < n / 2; i++). Integer division drops the remainder, so a 5-letter word gives 2 pairs and a 1-letter word gives none. - Compare
word[i]withword[n - 1 - i]. Fori = 0the partner is the last letter, at indexn - 1. If they differ,return falseat once. - Return
trueafter the loop. A one-letter word skips the loop and gets here. - In
PalindromeWords, create an emptyList<string>namedpalindromes. - Loop over
wordswithforeach, from the first word to the last, so the order is kept. - If
IsPalindrome(word)is true, add the word. The call returns abool, so it goes straight into theif. - Return
palindromes.
The solution in C#
class Solution {
public bool IsPalindrome(string word) {
int n = word.Length;
for (int i = 0; i < n / 2; i++) {
if (word[i] != word[n - 1 - i]) {
return false;
}
}
return true;
}
public List<string> PalindromeWords(string[] words) {
List<string> palindromes = new List<string>();
foreach (string word in words) {
if (IsPalindrome(word)) {
palindromes.Add(word);
}
}
return palindromes;
}
}
The details worth knowing:
- A string is indexed like an array,
word[i], and gives achar. Strings are immutable, so you can read characters but not assign to them. - The length of a string is the property
Length, with no parentheses. - Comparing two
charvalues with!=compares the characters themselves.
Watching the pairs
For "noon" the length is 4, so the loop makes two comparisons. The first compares the outer letters and the second the inner ones:
i=0: n vs n
i=1: o vs o
Both pairs match, so the loop ends and the method returns true. For "abca" the first pair is fine but the second is not:
i=0: a vs a
i=1: b vs c
At i = 1 the letters differ, so the method returns false without looking further. The same idea works with two index variables that start at both ends and move toward each other (while (i < j), then i++ and j--). That version gives the same answers on these words. The lesson's for version needs only one variable, because the partner's index follows from i and n.
Why the helper stays separate
The helper has its own loop, and PalindromeWords has another one. Keeping them apart means that neither loop has to deal with the other's variables: the helper thinks in letters and indexes, the outer method thinks in words. In the outer loop there is nothing to compute, only a question to ask once per word.
Testing
The helper gives these answers for a few small words:
a True
ab False
aba True
abca False
On the statement's three examples, PalindromeWords returns:
[pup, noon]
[a, bob, abba]
[]
Here the lists are printed with their values separated by commas; the lesson's tests print them with spaces.
Edge cases and common mistakes
- Using
word[n - i]as the partner. Ati = 0that is indexn, one past the last letter, and C# throws anIndexOutOfRangeException. The partner of indexiisn - 1 - i. - Returning
trueinside the loop. One matching pair proves nothing. Only a mismatch can end the check early. - Treating a one-letter word as a special case. It needs none:
1 / 2is 0, so the loop doesn't run and the method returnstrue. - Reversing the word. The lesson asks for the one-loop comparison from both ends.
Checking your own version
Test the helper on its own first. Good inputs are a one-letter word, a two-letter word that matches ("aa"), a two-letter word that doesn't ("ab"), an odd-length palindrome and an even-length one. Those cases catch the usual off-by-one slips in the loop limit and in the partner index.
Then run the full method on a list with a repeated palindrome. A word that appears twice must be kept twice, because the loop simply asks the helper about each word as it comes. The method never needs to remember which words it has already seen.
