3120. Count the Number of Special Characters I
Problem Description
You are given a string word
that contains letters. A letter is considered special if both its lowercase and uppercase versions appear somewhere in the string word
.
For example, if the string contains both 'a' and 'A', then the letter 'a'/'A' is special. However, if the string only contains 'b' but not 'B', then 'b' is not special.
Your task is to count how many distinct letters in word
are special and return this count.
The solution works by first creating a set s
containing all unique characters from the input string. Then it iterates through all 26 letters of the alphabet (using ascii_lowercase
and ascii_uppercase
which represent 'a-z' and 'A-Z' respectively). For each letter, it checks if both the lowercase and uppercase versions exist in the set. The sum()
function counts how many letter pairs satisfy this condition, giving us the total number of special letters.
Intuition
The key insight is that we need to check for the presence of matching letter pairs (lowercase and uppercase versions of the same letter). Since we only care about whether a character exists in the string or not, we can use a set to store all unique characters from the word - this gives us O(1) lookup time for checking existence.
Once we have all characters in a set, we need to systematically check each of the 26 possible letters to see if both versions are present. We can think of this as checking 26 pairs: ('a', 'A'), ('b', 'B'), ... ('z', 'Z').
Python's zip(ascii_lowercase, ascii_uppercase)
elegantly creates these pairs for us. For each pair (a, b)
, we check if both a in s
and b in s
. If both conditions are true, that letter is special.
Using sum()
with a generator expression is a concise way to count how many of these 26 pairs satisfy our condition - it treats True
as 1 and False
as 0, effectively counting the number of special letters.
This approach is efficient because we only make one pass through the input string to build the set, and then we perform a constant number of operations (26 checks) regardless of the input size.
Solution Approach
The solution uses a hash table (set) to efficiently track which characters appear in the string.
Step 1: Create a set of all characters
s = set(word)
We convert the input string word
into a set s
. This automatically removes duplicates and gives us all unique characters that appear in the string. The set provides O(1) lookup time for checking character existence.
Step 2: Check all 26 letter pairs
sum(a in s and b in s for a, b in zip(ascii_lowercase, ascii_uppercase))
This step breaks down into several parts:
ascii_lowercase
contains 'abcdefghijklmnopqrstuvwxyz'ascii_uppercase
contains 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'zip(ascii_lowercase, ascii_uppercase)
pairs them up: ('a', 'A'), ('b', 'B'), ..., ('z', 'Z')
Step 3: Count special letters
For each pair (a, b)
:
- Check if lowercase letter
a
exists in sets
- Check if uppercase letter
b
exists in sets
- If both exist (
a in s and b in s
evaluates toTrue
), this letter is special
The sum()
function counts how many pairs satisfy both conditions. Since Python treats True
as 1 and False
as 0, summing the boolean results gives us the total count of special letters.
Time Complexity: O(n) where n is the length of the input string (for creating the set) + O(26) for checking all letters = O(n)
Space Complexity: O(n) for storing the set of characters
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the string word = "aaAbcBC"
.
Step 1: Create a set of all characters
s = set("aaAbcBC")
# s = {'a', 'A', 'b', 'c', 'B', 'C'}
The set automatically removes duplicate 'a' characters and stores only unique characters.
Step 2: Check all 26 letter pairs
We'll iterate through each letter pair and check if both versions exist in our set:
-
For pair ('a', 'A'):
- 'a' in s? ✓ (Yes)
- 'A' in s? ✓ (Yes)
- Both exist → 'a' is special (count = 1)
-
For pair ('b', 'B'):
- 'b' in s? ✓ (Yes)
- 'B' in s? ✓ (Yes)
- Both exist → 'b' is special (count = 2)
-
For pair ('c', 'C'):
- 'c' in s? ✓ (Yes)
- 'C' in s? ✓ (Yes)
- Both exist → 'c' is special (count = 3)
-
For pair ('d', 'D'):
- 'd' in s? ✗ (No)
- 'D' in s? ✗ (No)
- Neither exist → 'd' is not special
-
... (continuing for remaining letters e-z, none of which appear in our string)
Step 3: Return the count
The sum function counts all the True
values (where both lowercase and uppercase exist):
- Letters a, b, and c are special
- Total count = 3
Therefore, the function returns 3 as the number of special letters in "aaAbcBC".
Solution Implementation
1class Solution:
2 def numberOfSpecialChars(self, word: str) -> int:
3 """
4 Count the number of special characters where both lowercase and uppercase versions exist.
5
6 A character is considered special if both its lowercase and uppercase forms
7 appear in the given word.
8
9 Args:
10 word: Input string to check for special characters
11
12 Returns:
13 Number of special character pairs found in the word
14 """
15 # Import required constants for ASCII letters
16 from string import ascii_lowercase, ascii_uppercase
17
18 # Convert word to set for O(1) lookup of characters
19 char_set = set(word)
20
21 # Count pairs where both lowercase and uppercase versions exist
22 # zip pairs each lowercase letter with its corresponding uppercase letter
23 special_count = sum(
24 lower_char in char_set and upper_char in char_set
25 for lower_char, upper_char in zip(ascii_lowercase, ascii_uppercase)
26 )
27
28 return special_count
29
1class Solution {
2 public int numberOfSpecialChars(String word) {
3 // Create a boolean array to track presence of characters
4 // Size is 'z' + 1 (123) to accommodate all uppercase and lowercase letters
5 boolean[] characterPresence = new boolean['z' + 1];
6
7 // Iterate through each character in the word
8 for (int i = 0; i < word.length(); i++) {
9 // Mark the character as present using its ASCII value as index
10 characterPresence[word.charAt(i)] = true;
11 }
12
13 // Initialize counter for special characters
14 int specialCharCount = 0;
15
16 // Check each letter from 'a' to 'z' (26 letters total)
17 for (int i = 0; i < 26; i++) {
18 // A character is special if both its lowercase and uppercase forms exist
19 if (characterPresence['a' + i] && characterPresence['A' + i]) {
20 specialCharCount++;
21 }
22 }
23
24 // Return the total count of special characters
25 return specialCharCount;
26 }
27}
28
1class Solution {
2public:
3 int numberOfSpecialChars(string word) {
4 // Create a boolean array to track presence of each character
5 // Size is 'z' + 1 to accommodate all ASCII values from 0 to 'z'
6 vector<bool> charPresent('z' + 1, false);
7
8 // Mark each character in the word as present
9 for (char& ch : word) {
10 charPresent[ch] = true;
11 }
12
13 // Count letters that appear in both lowercase and uppercase
14 int specialCharCount = 0;
15 for (int i = 0; i < 26; ++i) {
16 // Check if both lowercase and uppercase versions exist
17 if (charPresent['a' + i] && charPresent['A' + i]) {
18 specialCharCount++;
19 }
20 }
21
22 return specialCharCount;
23 }
24};
25
1/**
2 * Counts the number of special characters in a word.
3 * A character is considered special if both its lowercase and uppercase versions appear in the word.
4 *
5 * @param word - The input string to analyze
6 * @returns The count of special characters (letters that appear in both cases)
7 */
8function numberOfSpecialChars(word: string): number {
9 // Create a boolean array to track which ASCII characters are present
10 // Array size is 'z' ASCII value + 1 to cover all lowercase letters
11 const characterPresence: boolean[] = Array.from(
12 { length: 'z'.charCodeAt(0) + 1 },
13 () => false
14 );
15
16 // Mark each character in the word as present in the array
17 for (let i = 0; i < word.length; i++) {
18 const asciiCode = word.charCodeAt(i);
19 characterPresence[asciiCode] = true;
20 }
21
22 // Count letters that appear in both lowercase and uppercase
23 let specialCharCount: number = 0;
24
25 // Check all 26 letters of the alphabet
26 for (let i = 0; i < 26; i++) {
27 const lowercaseAscii = 'a'.charCodeAt(0) + i;
28 const uppercaseAscii = 'A'.charCodeAt(0) + i;
29
30 // If both lowercase and uppercase versions are present, increment counter
31 if (characterPresence[lowercaseAscii] && characterPresence[uppercaseAscii]) {
32 specialCharCount++;
33 }
34 }
35
36 return specialCharCount;
37}
38
Time and Space Complexity
The time complexity is O(n + |Σ|)
, where n
is the length of the string word
and |Σ|
is the size of the character set. Breaking this down:
- Creating the set from
word
takesO(n)
time as it needs to iterate through each character - The
zip(ascii_lowercase, ascii_uppercase)
creates 26 pairs, so the loop runsO(26) = O(|Σ|)
times - Each membership check (
in s
) takesO(1)
average time for a set - Therefore, total time complexity is
O(n) + O(|Σ|) = O(n + |Σ|)
The space complexity is O(|Σ|)
, where |Σ|
represents the size of the character set. This is because:
- The set
s
stores unique characters fromword
, which can be at mostO(|Σ|)
characters - The
zip
operation and iteration use constant extra space - In this problem,
|Σ| ≤ 128
since we're dealing with ASCII characters (both uppercase and lowercase letters)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Counting Duplicate Occurrences
A common mistake is counting the same special letter multiple times when it appears in different positions in the string.
Incorrect Approach:
def numberOfSpecialChars(self, word: str) -> int:
count = 0
for char in word:
if char.islower() and char.upper() in word:
count += 1
elif char.isupper() and char.lower() in word:
count += 1
return count
Problem: If the word is "aAbBcC", this would count 'a' twice (once when encountering 'a' and once when encountering 'A'), resulting in an incorrect count of 6 instead of 3.
Solution: Use a set to track which letters have already been identified as special, or check all 26 letters exactly once as in the correct solution.
Pitfall 2: Case Sensitivity in Set Operations
Another mistake is trying to use case-insensitive comparisons incorrectly.
Incorrect Approach:
def numberOfSpecialChars(self, word: str) -> int:
lower_chars = set(word.lower())
upper_chars = set(word.upper())
# This doesn't work because both sets contain the same letters
return len(lower_chars & upper_chars)
Problem: Converting the entire word to lowercase or uppercase loses the information about which case versions actually exist in the original string.
Solution: Preserve the original cases by working with the original string's character set.
Pitfall 3: Inefficient Character-by-Character Checking
Checking each character against every other character in the string leads to poor performance.
Incorrect Approach:
def numberOfSpecialChars(self, word: str) -> int:
special = set()
for i, char in enumerate(word):
for j, other in enumerate(word):
if i != j and char.swapcase() == other:
special.add(char.lower())
return len(special)
Problem: This has O(n²) time complexity, which is inefficient for large strings.
Solution: Use the set-based approach with O(n) complexity as shown in the correct solution, checking only the 26 possible letter pairs once.
What are the two properties the problem needs to have for dynamic programming to be applicable? (Select 2)
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!