[LeetCode] 1358. Number of Substrings Containing All Three Characters 包含所有三种字符的子字符串数目


Given a string s consisting only of characters ab and c.

Return the number of substrings containing at least one occurrence of all these characters ab and c.

Example 1:

Input: s = "abcabc"
Output: 10
Explanation: The substrings containing at least one occurrence of the characters ab and c are "abc", "abca", "abcab", "abcabc", "bca", "bcab", "bcabc", "cab", "cabc" and "abc" (again).

Example 2:

Input: s = "aaacb"
Output: 3
Explanation: The substrings containing at least one occurrence of the characters ab and c are "aaacb", "aacb" and "acb".

Example 3:

Input: s = "abc"
Output: 1

Constraints:

  • 3 <= s.length <= 5 x 10^4
  • s only consists of ab or *c *characters.

这道题给了一个只有 a,b,c 三个字母构成的字符串s,现在让找出三个字母均至少出现一次的子串的个数。一般玩字符串的题目无外乎就是滑动窗口 Sliding Window 和动态规划 Dynamic Programming 用的比较多。这道题不太适合用 DP,状态转移方程不太好找。来看看能否用滑动窗口来做吧,如果题目让求的是三个字母都只出现一次的话,想必大家应该都没啥问题,这里的至少出现一次也算是个难点了,就拿例子1来分析,当滑动窗口套住第一个 abc 的时候,此时除了其本身是符合要求的,其后面的每个字母都可以跟窗口里的字母组成符合要求的子串,组成 abca, abcab, abcabc,这样统计的个数世纪上就是 n-i,n是原字符串s的总长度,i是当前滑动窗口的右边界,整个步骤如下所示:

[a b c] a b c
abc, abca, abcab, ababc

a [b c a] b c
bca, bcab, bcabc

a b [c a b] c
cab, cabc

a b c [a b c]
abc

通过上面这种计数方法,我们就可以不重复的统计出所有满足情况的子串。当然这种统计方法也不是唯一的,比如 lee215 大神用的就是另一种统计方法,其主要是统计左边界前面的字母个数,也是可以的,参见代码如下:


解法一:

class Solution {
public:
    int numberOfSubstrings(string s) {
        int res = 0, n = s.size(), left = 0;
        vector<int> cnt(3);
        for (int i = 0; i < n; ++i) {
            ++cnt[s[i] - 'a'];
            while (cnt[0] && cnt[1] && cnt[2]) {
                res += n - i;
                --cnt[s[left++] - 'a'];
            }
        }
        return res;
    }
};

再来看一种更加简洁的解法,这里记录 a,b,c 最后出现的位置,初始化为-1,然后每次取其中最小的数字,再加上1就是当前范围内符合要求的子串的个数。当最小值为初始的 -1 时,说明某个字母没有出现过,则加上0不影响结果,而当最小的大于等于0了,说明每个字母都出现过了,而最小的那个值就相当于滑动窗口的左边界,其实还是统计左边界前面的字母个数,参见计数过程如下:

a b c a b c

i = 0, [0, -1, -1], min = -1
i = 1, [0, 1, -1], min = -1
i = 2, [0, 1, 2], min = 0 -> abc
i = 3, [3, 1, 2], min = 1 -> abca, bca
i = 4, [3, 4, 2], min = 2 -> abcab, bcab, cab
i = 5, [3, 4, 5], min = 3 -> abcabc, bcabc, cabc, abc

解法二:

class Solution {
public:
    int numberOfSubstrings(string s) {
        int res = 0, n = s.size();
        vector<int> last(3, -1);
        for (int i = 0; i < n; ++i) {
            last[s[i] - 'a'] = i;
            res += 1 + min({last[0], last[1], last[2]});
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1358


类似题目:

Vowels of All Substrings


参考资料:

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters/solutions/516977/java-c-python-easy-and-concise/

https://leetcode.com/problems/number-of-substrings-containing-all-three-characters/solutions/3459766/explained-w-images-made-easy-c/


LeetCode All in One 题目讲解汇总(持续更新中...)

posted @ 2023-10-30 05:48  Grandyang  阅读(89)  评论(0编辑  收藏  举报
Fork me on GitHub