3120. Count the Number of Special Characters I
題目 / Problem
給你一個字串 word。如果某個字母同時以小寫和大寫出現在 word 中,這個字母就被稱為特殊字母(special)。請回傳 word 中特殊字母的數量。
You are given a string word. A letter is called special if it appears both in lowercase and uppercase in word. Return the number of special letters in word.
約束 / Constraints:
- 1 <= word.length <= 50
- word 只由大小寫英文字母組成 / word consists of only lowercase and uppercase English letters.
範例 / Example: word = "aaAbcBC" → 輸出 3。因為 'a'(有 a 和 A)、'b'(有 b 和 B)、'c'(有 c 和 C)三個字母都同時出現了大小寫,所以答案是 3。
名詞解釋 / Glossary
- ASCII 值 / ASCII value:每個字元在電腦裡其實是一個整數。例如
'a'是 97,'A'是 65。把字元當數字用,就能做減法算出它是第幾個字母。 / Every character is secretly an integer.'a'is 97,'A'is 65. Treating chars as numbers lets us index arrays. - 布林陣列 / boolean array:一個只存「真/假」的陣列。我們用
seenLower[26]記錄 26 個小寫字母各自有沒有出現過。 / An array storing only true/false. We use it to record whether each of the 26 letters has appeared. - 字元映射成索引 / mapping a char to an index:用
c - 'a'把'a'..'z'變成0..25,這樣就能當陣列下標使用。 / Usec - 'a'to turn'a'..'z'into0..25so it can be an array subscript. - 原地遍歷 / single pass:只把字串從頭到尾掃一遍,不需要巢狀迴圈。 / Scanning the string once, front to back, with no nested loop.
思路
最直接的暴力想法是:對 26 個字母中的每一個,掃一遍字串看看小寫版本在不在,再掃一遍看看大寫版本在不在,兩個都在就計數加一。因為字串長度最多只有 50,這樣做 26 × 50 × 2 次完全沒問題,但它重複掃描了很多次,不夠優雅。更好的做法是反過來:只掃字串一次,邊掃邊記錄「我看過哪些小寫字母」和「我看過哪些大寫字母」。我們開兩個長度 26 的布林陣列 seenLower 和 seenUpper,遇到小寫字母 c 就把 seenLower[c-'a'] 設為真,遇到大寫字母就把 seenUpper[c-'A'] 設為真。掃完之後,再從 0 到 25 檢查每個字母編號 i:如果 seenLower[i] 和 seenUpper[i] 同時為真,代表這個字母大小寫都出現過,就是特殊字母,計數加一。這裡的關鍵是用「字母編號」(0..25)把同一個字母的大寫和小寫對齊到同一個位置——'a' 和 'A' 都對應編號 0,所以我們能在最後一步比對它們。
The brute-force idea is: for each of the 26 letters, scan the string to see if its lowercase form exists, scan again for its uppercase form, and count it if both are present. Since the string is at most 50 characters, doing 26 × 50 × 2 checks is fine, but it rescans the string wastefully. A cleaner approach flips it around: scan the string just once while recording which lowercase letters and which uppercase letters we have seen. We keep two boolean arrays of length 26, seenLower and seenUpper. For a lowercase char c we set seenLower[c-'a'] = true; for an uppercase char we set seenUpper[c-'A'] = true. After the pass, we loop i from 0 to 25 and count every i where both seenLower[i] and seenUpper[i] are true — that letter appears in both cases, so it is special. The trick is using the letter's index (0..25) to align the uppercase and lowercase versions of the same letter to the same slot: both 'a' and 'A' map to index 0, letting us compare them at the end.
逐步走查 / Walkthrough
輸入 / Input: word = "aaAbcBC"。兩個陣列一開始全是 false。逐字處理 / Process char by char:
| 步驟 / Step | 字元 / Char | 動作 / Action | seenLower(被設真的位置) | seenUpper(被設真的位置) |
|---|---|---|---|---|
| 1 | a |
小寫,設 seenLower[0]=true | {a} | {} |
| 2 | a |
小寫,seenLower[0] 已是 true | {a} | {} |
| 3 | A |
大寫,設 seenUpper[0]=true | {a} | {A} |
| 4 | b |
小寫,設 seenLower[1]=true | {a,b} | {A} |
| 5 | c |
小寫,設 seenLower[2]=true | {a,b,c} | {A} |
| 6 | B |
大寫,設 seenUpper[1]=true | {a,b,c} | {A,B} |
| 7 | C |
大寫,設 seenUpper[2]=true | {a,b,c} | {A,B,C} |
最後比對 / Final comparison(檢查每個編號 i 是否兩邊都為真): - i=0(字母 a):lower ✓、upper ✓ → 特殊,count=1 - i=1(字母 b):lower ✓、upper ✓ → 特殊,count=2 - i=2(字母 c):lower ✓、upper ✓ → 特殊,count=3 - i=3..25:兩邊皆 false → 跳過
答案 / Answer: 3 ✓
Solution — C
// 演算法 / Algorithm:
// 掃字串一次,用兩個布林陣列分別記下出現過的小寫與大寫字母;
// 最後數出有幾個字母編號同時在兩個陣列中為真。
// Scan once, mark seen lowercase/uppercase letters in two boolean arrays,
// then count letter indices that are true in BOTH arrays.
int numberOfSpecialChars(char* word) {
bool seenLower[26] = {false}; // 26 個小寫字母看過沒 / has each lowercase letter been seen
bool seenUpper[26] = {false}; // 26 個大寫字母看過沒 / has each uppercase letter been seen
// 從頭掃到字串結尾的 '