[LeetCode] 1358. Number of Substrings Containing All Three Characters 包含所有三种字符的子字符串数目
Given a string s
consisting only of characters a, b and c.
Return the number of substrings containing at least one occurrence of all these characters a, b and c.
Example 1:
Input: s = "abcabc"
Output: 10
Explanation: The substrings containing at least one occurrence of the characters a, b 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 a, b 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 a, b 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