题目描述
如果一个字符串不含有任何重复字符,我们称这个字符串为 好 字符串。
给你一个字符串 s
,请你返回 s
中长度为 3 的 好子字符串 的数量。
注意,如果相同的好子字符串出现多次,每一次都应该被记入答案之中。
子字符串 是一个字符串中连续的字符序列。
示例 1:
输入:s = "xyzzaz"
输出:1
解释:总共有 4 个长度为 3 的子字符串:"xyz","yzz","zza" 和 "zaz" 。
唯一的长度为 3 的好子字符串是 "xyz" 。
示例 2:
输入:s = "aababcabc"
输出:4
解释:总共有 7 个长度为 3 的子字符串:"aab","aba","bab","abc","bca","cab" 和 "abc" 。
好子字符串包括 "abc","bca","cab" 和 "abc" 。
提示:
1 <= s.length <= 100
s
只包含小写英文字母。
解法
方法一:滑动窗口
我们可以维护一个滑动窗口,使得窗口内的字符不重复。初始时,我们用一个长度为 $26$ 的二进制整数 $\textit{mask}$ 表示窗口内的字符,其中第 $i$ 位为 $1$ 表示字符 $i$ 在窗口内出现过,否则表示字符 $i$ 在窗口内没有出现过。
然后,我们遍历字符串 $s$,对于每一个位置 $r$,如果 $\textit{s}[r]$ 在窗口内出现过,我们需要将窗口的左边界 $l$ 右移,直到窗口内不再有重复的字符。在这之后,我们将 $\textit{s}[r]$ 加入窗口内,此时如果窗口的长度大于等于 $3$,那么我们就找到了一个以 $\textit{s}[r]$ 结尾的长度为 $3$ 的好子字符串。
遍历结束后,我们就找到了所有的好子字符串的数量。
时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(1)$。
该解法可以拓展到长度为 $k$ 的好子字符串的数量。
| class Solution:
def countGoodSubstrings(self, s: str) -> int:
ans = mask = l = 0
for r, x in enumerate(map(lambda c: ord(c) - 97, s)):
while mask >> x & 1:
y = ord(s[l]) - 97
mask ^= 1 << y
l += 1
mask |= 1 << x
ans += int(r - l + 1 >= 3)
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | class Solution {
public int countGoodSubstrings(String s) {
int ans = 0;
int n = s.length();
for (int l = 0, r = 0, mask = 0; r < n; ++r) {
int x = s.charAt(r) - 'a';
while ((mask >> x & 1) == 1) {
int y = s.charAt(l++) - 'a';
mask ^= 1 << y;
}
mask |= 1 << x;
ans += r - l + 1 >= 3 ? 1 : 0;
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | class Solution {
public:
int countGoodSubstrings(string s) {
int ans = 0;
int n = s.length();
for (int l = 0, r = 0, mask = 0; r < n; ++r) {
int x = s[r] - 'a';
while ((mask >> x & 1) == 1) {
int y = s[l++] - 'a';
mask ^= 1 << y;
}
mask |= 1 << x;
ans += r - l + 1 >= 3 ? 1 : 0;
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | func countGoodSubstrings(s string) (ans int) {
mask, l := 0, 0
for r, c := range s {
x := int(c - 'a')
for (mask>>x)&1 == 1 {
y := int(s[l] - 'a')
l++
mask ^= 1 << y
}
mask |= 1 << x
if r-l+1 >= 3 {
ans++
}
}
return
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | function countGoodSubstrings(s: string): number {
let ans = 0;
const n = s.length;
for (let l = 0, r = 0, mask = 0; r < n; ++r) {
const x = s.charCodeAt(r) - 'a'.charCodeAt(0);
while ((mask >> x) & 1) {
const y = s.charCodeAt(l++) - 'a'.charCodeAt(0);
mask ^= 1 << y;
}
mask |= 1 << x;
ans += r - l + 1 >= 3 ? 1 : 0;
}
return ans;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | class Solution {
/**
* @param String $s
* @return Integer
*/
function countGoodSubstrings($s) {
$ans = 0;
$n = strlen($s);
$l = 0;
$r = 0;
$mask = 0;
while ($r < $n) {
$x = ord($s[$r]) - ord('a');
while (($mask >> $x) & 1) {
$y = ord($s[$l++]) - ord('a');
$mask ^= 1 << $y;
}
$mask |= 1 << $x;
if ($r - $l + 1 >= 3) {
$ans++;
}
$r++;
}
return $ans;
}
}
|