S2Q1 · Count Words with Matching First/Last but Different Second/Second-Last¶
⚡ Quick Reference
Function: count_special(words: list) -> int
Core idea: for each word, check if first == last AND second != second-last (case-insensitive).
def count_special(words):
count = 0
for w in words:
w = w.lower()
if w[0] == w[-1] and w[1] != w[-2]:
count += 1
return count
Key rules:
- Case-insensitive → lowercase the whole word first
- Condition 1: w[0] == w[-1] (first == last)
- Condition 2: w[1] != w[-2] (second ≠ second-last)
- Both must hold; each word has at least 2 characters
Problem Statement¶
Problem
Write a function count_special(words) that counts how many words have the same first and last character AND different second and second-last characters (case-insensitively).
Examples:
["Bulb", "deed", "civic", "Noon", "lol"]
1
["abca", "aXba", "xyzzyx", "abcaXab"]
2
Tracing both examples¶
Example 1: ["Bulb", "deed", "civic", "Noon", "lol"]
| Word | lowered | w[0]==w[-1]? |
w[1]!=w[-2]? |
Count? |
|---|---|---|---|---|
"Bulb" |
"bulb" |
b==b ✅ | u!=l ✅ | ✅ |
"deed" |
"deed" |
d==d ✅ | e!=e ❌ | ❌ |
"civic" |
"civic" |
c==c ✅ | i!=i ❌ | ❌ |
"Noon" |
"noon" |
n==n ✅ | o!=o ❌ | ❌ |
"lol" |
"lol" |
l==l ✅ | o!=o ❌ | ❌ |
Count = 1 ✓
Example 2: ["abca", "aXba", "xyzzyx", "abcaXab"]
| Word | lowered | [0]==[−1]? |
[1]!=[−2]? |
Count? |
|---|---|---|---|---|
"abca" |
"abca" |
a==a ✅ | b!=c ✅ | ✅ |
"aXba" |
"axba" |
a==a ✅ | x!=b ✅ | ✅ |
"xyzzyx" |
"xyzzyx" |
x==x ✅ | y!=y ❌ | ❌ |
"abcaXab" |
"abcaxab" |
a!=b ❌ | - | ❌ |
Count = 2 ✓
Solution approaches¶
Key takeaways¶
Lowercase the whole word once
w = w.lower() upfront makes all four index accesses case-insensitive without repeated .lower() calls per character. One conversion covers all conditions.
w[1] and w[-2] - second and second-last
w[1] is the second character; w[-2] is the second-to-last. For a 2-character word like "ab", w[1] == w[-2] (both index position 1 and -1 from the end coincide at index 1) - this correctly handles the edge case.
Short-circuit and - skip second check if first fails
w[0] == w[-1] and w[1] != w[-2] - if the first/last don't match, the second condition is never evaluated. Words failing condition 1 are skipped efficiently.