Read Both Ways
An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- easy
- Seniority
- junior
- Asked in
- Tata Consultancy Services
Problem
We sweep production records for placeholder identifiers that QA seeds as values reading the same forwards and backwards, so they are easy to spot and purge later. Scan a batch of tokens and return the ones that still read the same in both directions once you ignore case and any character that is not a letter or digit, keeping them in the order they appeared. A token with no letters or digits at all does not count.
Placeholders hide in plain sight. The symmetric ones give themselves away.
Example 1
Input:
tokens = ["Race-car","data2024","A man, a plan","Level"]
Output:
["Race-car","Level"]
Example 2
Input:
tokens = ["!!!","x","noon"]
Output:
["x","noon"]
Worked solution and explanation
What this is really testing
Strip the QA-placeholder costume and this is a filter with a normalization step hiding inside a symmetry check. Anyone can write the reverse-compare; the part that actually separates candidates is recognizing that the raw token is not what you compare. 'Race-car' is not equal to its own reverse as a raw string, and '!!!' looks symmetric but carries no real value. The candidate who normalizes first (case-fold, keep only letters and digits) and then guards against the empty result gets the right set. The one who writes the one-liner over raw strings misses real flags and invents fake ones.
Break down the requirements
Step 1: Normalize each token before judging it
Lowercase every character and keep only the ones where c.isalnum() is true. This is the load-bearing step: it turns 'Race-car' into 'racecar' so the comparison can succeed, and it is what a raw reverse-compare skips.
Step 2: Compare the cleaned form to its reverse
Once normalized, cleaned == cleaned[::-1] is the symmetry test. Slicing with [::-1] reverses the string in one expression and reads exactly like the spec sentence.
Step 3: Reject tokens that normalize to nothing
A token like '!!!' becomes the empty string after normalization, and the empty string equals its own reverse, so without a guard it would be flagged. The prompt says a token with no letters or digits does not count, so require cleaned to be non-empty.
Step 4: Append the ORIGINAL token, in order
Collect the untouched input token, not its normalized form, and append as you walk the list so input order is preserved for free.
The solution
def find_palindromes(tokens):
flagged = []
for token in tokens:
cleaned = "".join(c.lower() for c in token if c.isalnum())
if cleaned and cleaned == cleaned[::-1]:
flagged.append(token)
return flaggedCommon follow-up questions
- How would you change this to also report WHERE in each token the symmetry breaks for the non-matching ones? (Pushes from a boolean predicate to a two-pointer walk that returns the first mismatched index pair.)
- The tokens now arrive as a stream too large to hold in memory. How do you adapt? (Tests turning the list comprehension into a generator that yields flagged tokens lazily.)
- What if symmetry should be checked on the raw characters, punctuation and all, with only case ignored? (Probes whether the candidate can isolate and adjust the normalization rule without rewriting the comparison.)