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,求这三个字符至少出现一次的子串个数。

直接的想法是计算这三个字符出现次数的前缀和,然后使用滑动窗口。使用前缀和来判断窗口内的子串是否满足条件,如果 [l, r] 满足条件,那么 [l, r ~ n - 1] 也满足条件。

判断字符是否至少出现一次可以不用前缀和,使用三个变量记录它们上次出现的下标,如果小于左端点则用 -1 标记。

代码


/**
 * @date 2026-06-30 9:14
 */
public class NumberOfSubstrings1358 {

    public int numberOfSubstrings(String s) {
        int n = s.length();
        int a = -1, b = -1, c = -1;
        int l = 0;
        int res = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == 'a') {
                a = i;
            } else if (s.charAt(i) == 'b') {
                b = i;
            } else {
                c = i;
            }
            while (a >= 0 && b >= 0 && c >= 0) {
                res += n - i;
                if (a <= l) {
                    a = -1;
                } else if (b <= l) {
                    b = -1;
                } else if (c <= l) {
                    c = -1;
                }
                l++;
            }
        }
        return res;
    }

}

性能