给你一个字符串 word。如果 word 中同时出现某个字母 c 的小写形式和大写形式,并且每个 小写形式的 c 都出现在第一个大写形式的 c 之前,则称字母 c 是一个 特殊字母 。
返回 word 中 特殊字母 的数量。
示例 1:
**输入:**word = "aaAbcBC"
**输出:**3
解释:
特殊字母是 'a'、'b' 和 'c'。
示例 2:
**输入:**word = "abc"
**输出:**0
解释:
word 中不存在特殊字母。
示例 3:
**输入:**word = "AbBCab"
**输出:**0
解释:
word 中不存在特殊字母。
提示:
1 <= word.length <= 2 * 10^5word仅由小写和大写英文字母组成。
分析:从左到右扫描字符串,记录每个字母当前的状态。
lowwer[i] 表示在出现大写字母之前,已经遇到过多少个对应的小写字母。
upper[i] 表示对应的大写字母出现次数,不过这份代码中它对最终判断没有实际影响,只是进行了记录。
flag[i] 表示当前字母是否已经出现过大写形式。
ans 表示目前暂时满足条件的特殊字母数量。
set<int>st 用来记录后来被判定为不合法的字母。
扫描字符串时,分两种情况讨论。如果当前字符是大写字母,例如 'A',先计算它对应的下标。如果这个字母之前还没有出现过大写形式,并且之前已经出现过小写形式,说明它暂时满足"小写在前,大写在后"的条件,因此答案加一,然后将 flag[val] 置为 1,表示这个字母的大写形式已经出现过。
如果当前字符是小写字母,例如 'a',同样先计算下标。此时需要判断这个小写字母是不是出现在了对应大写字母之后。如果 flag[val] 为真,说明之前已经出现过对应的大写字母。此时如果 lowwer[val] 也为真,说明这个字母原本已经被计入答案,但是现在又在大写字母后面出现了小写字母,违反了题目要求,所以要把这个字母加入 st,表示它应该从答案中扣除:st.insert(val);
如果 flag[val] 为真,但是 lowwer[val] 为假,说明是先出现了大写字母,后出现了小写字母。这种情况本来就不会被计入 ans,因此直接跳过即可。
如果 flag[val] 为假,说明目前还没有出现过对应的大写字母,那么这个小写字母是合法出现在前面的,记录下来。
最后,ans 中记录的是曾经满足"小写在前,大写在后"的字母数量,而 st 中记录的是后来又出现小写字母、因此变得不合法的字母数量。所以最终答案为:ans - st.size();
cpp
class Solution {
public:
int numberOfSpecialChars(string word) {
int n=word.length(),lowwer[30]={0},upper[30]={0},flag[30]={0},ans=0;
set<int>st;
for(int i=0;i<n;++i)
{
if(word[i]>='A'&&word[i]<='Z')
{
int val=word[i]-'A';
upper[val]++;
if(!flag[val]&&lowwer[val])flag[val]=1,ans++;
flag[val]=1;
}
else if(word[i]>='a'&&word[i]<='z')
{
int val=word[i]-'a';
if(flag[val]&&lowwer[val])st.insert(val);
else if(flag[val])continue;
else lowwer[val]++;
}
}
return ans-st.size();
}
};