leetcode 1358. 包含所有三种字符的子字符串数目 中等

给你一个字符串 s ,它只包含三种字符 a, b 和 c 。

请你返回 a,b 和 c 都 至少出现过一次的子字符串数目。

示例 1:

复制代码
输入:s = "abcabc"
输出:10
解释:包含 a,b 和 c 各至少一次的子字符串为 "abc", "abca", "abcab", "abcabc", "bca", "bcab", "bcabc", "cab", "cabc" 和 "abc" (相同字符串算多次)。

示例 2:

复制代码
输入:s = "aaacb"
输出:3
解释:包含 a,b 和 c 各至少一次的子字符串为 "aaacb", "aacb" 和 "acb" 。

示例 3:

复制代码
输入:s = "abc"
输出:1

提示:

  • 3 <= s.length <= 5 x 10^4
  • s 只包含字符 a,b 和 c 。

分析:如果字符串的某个字串中 a,b,c 都至少出现过一次,则从这个字串开始,向右增长的子串一定全部符合题目要求。假设当前子串在原字符串 s 中出现在下标 j,i,则 j,i+1, j,i+2,······,j,s.length()-1 这些所有的字符串都符合条件,总共 length-i 个。

因此可以用双指针,j 指向当前字符串的开头,i 指向当前字符串的末尾,一个数组 cnt3 代表 a,b,c 三个字符出现的次数。当 cnt0、cnt1、cnt2 都不为空时,说明当前子串 j,i 中 a,b,c 都至少出现过一次,此时答案增加 length-i,并将 j 向右移动,直到新的字串不符合题目要求位置。这样遍历完整个字符串即可得到答案。

cpp 复制代码
class Solution {
public:
    int numberOfSubstrings(string s) {
        int ans=0,len=s.length(),cnt[5]={0};cnt[s[0]-'a']++;
        for(int i=1,j=0;s[i];++i)
        {
            cnt[s[i]-'a']++;
            while(i-j>=2&&cnt[0]&&cnt[1]&&cnt[2])
                ans+=len-i,cnt[s[j]-'a']--,++j;
        }
        return ans;
    }
};