Count the Number of Special Characters II

medium hash table string indexing

Problem

Given a string word, a letter c is special if it appears in both lowercase and uppercase, and every lowercase occurrence of c appears before the first uppercase occurrence of c. Return how many letters are special.

Equivalently, a letter is special when the last index of its lowercase form is less than the first index of its uppercase form (and both forms appear).

Inputword = "aaAbcBC"
Output3
The special letters are 'a', 'b', and 'c': each lowercase run finishes before its uppercase appears.

def numberOfSpecialChars(word):
    first_upper = {}          # letter -> first index seen uppercase
    last_lower = {}           # letter -> last index seen lowercase
    for i, ch in enumerate(word):
        if ch.islower():
            last_lower[ch] = i             # always overwrite: keep latest
        else:
            low = ch.lower()
            if low not in first_upper:
                first_upper[low] = i       # only the first uppercase index
    count = 0
    for c in last_lower:
        # special: lowercase exists, uppercase exists, all lowers come first
        if c in first_upper and last_lower[c] < first_upper[c]:
            count += 1
    return count
function numberOfSpecialChars(word) {
  const firstUpper = {};            // letter -> first uppercase index
  const lastLower = {};             // letter -> last lowercase index
  for (let i = 0; i < word.length; i++) {
    const ch = word[i];
    if (ch >= "a" && ch <= "z") {
      lastLower[ch] = i;            // overwrite: keep latest lowercase
    } else {
      const low = ch.toLowerCase();
      if (!(low in firstUpper)) firstUpper[low] = i; // first uppercase only
    }
  }
  let count = 0;
  for (const c in lastLower) {
    // all lowers before first upper, and both forms present
    if (c in firstUpper && lastLower[c] < firstUpper[c]) count++;
  }
  return count;
}
int numberOfSpecialChars(String word) {
    int[] firstUpper = new int[26];   // first uppercase index, -1 if none
    int[] lastLower = new int[26];    // last lowercase index, -1 if none
    Arrays.fill(firstUpper, -1);
    Arrays.fill(lastLower, -1);
    for (int i = 0; i < word.length(); i++) {
        char ch = word.charAt(i);
        if (ch >= 'a' && ch <= 'z') {
            lastLower[ch - 'a'] = i;              // keep latest lowercase
        } else if (firstUpper[ch - 'A'] == -1) {
            firstUpper[ch - 'A'] = i;            // first uppercase only
        }
    }
    int count = 0;
    for (int c = 0; c < 26; c++) {
        // both forms present and all lowers before first upper
        if (lastLower[c] != -1 && firstUpper[c] != -1 && lastLower[c] < firstUpper[c]) count++;
    }
    return count;
}
int numberOfSpecialChars(string word) {
    vector<int> firstUpper(26, -1);   // first uppercase index, -1 if none
    vector<int> lastLower(26, -1);    // last lowercase index, -1 if none
    for (int i = 0; i < (int)word.size(); i++) {
        char ch = word[i];
        if (ch >= 'a' && ch <= 'z') {
            lastLower[ch - 'a'] = i;             // keep latest lowercase
        } else if (firstUpper[ch - 'A'] == -1) {
            firstUpper[ch - 'A'] = i;           // first uppercase only
        }
    }
    int count = 0;
    for (int c = 0; c < 26; c++) {
        // both forms present and all lowers before first upper
        if (lastLower[c] != -1 && firstUpper[c] != -1 && lastLower[c] < firstUpper[c]) count++;
    }
    return count;
}
Time: O(n) Space: O(1) (26 letters)