Skip to content

Commit 9eda464

Browse files
authored
feat: add solutions to lc problem: No.3329 (doocs#3661)
No.3329.Count Substrings With K-Frequency Characters II
1 parent c66687a commit 9eda464

File tree

9 files changed

+431
-0
lines changed

9 files changed

+431
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
---
2+
comments: true
3+
difficulty: 困难
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3329.Count%20Substrings%20With%20K-Frequency%20Characters%20II/README.md
5+
tags:
6+
- 滑动窗口
7+
---
8+
9+
<!-- problem:start -->
10+
11+
# [3329. Count Substrings With K-Frequency Characters II 🔒](https://leetcode.cn/problems/count-substrings-with-k-frequency-characters-ii)
12+
13+
[English Version](/solution/3300-3399/3329.Count%20Substrings%20With%20K-Frequency%20Characters%20II/README_EN.md)
14+
15+
## 题目描述
16+
17+
<!-- description:start -->
18+
19+
<p>Given a string <code>s</code> and an integer <code>k</code>, return the total number of <span data-keyword="substring-nonempty">substrings</span> of <code>s</code> where <strong>at least one</strong> character appears <strong>at least</strong> <code>k</code> times.</p>
20+
21+
<p>&nbsp;</p>
22+
<p><strong class="example">Example 1:</strong></p>
23+
24+
<div class="example-block">
25+
<p><strong>Input:</strong> <span class="example-io">s = &quot;abacb&quot;, k = 2</span></p>
26+
27+
<p><strong>Output:</strong> <span class="example-io">4</span></p>
28+
29+
<p><strong>Explanation:</strong></p>
30+
31+
<p>The valid substrings are:</p>
32+
33+
<ul>
34+
<li>&quot;<code>aba&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
35+
<li><code>&quot;abac&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
36+
<li><code>&quot;abacb&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
37+
<li><code>&quot;bacb&quot;</code> (character <code>&#39;b&#39;</code> appears 2 times).</li>
38+
</ul>
39+
</div>
40+
41+
<p><strong class="example">Example 2:</strong></p>
42+
43+
<div class="example-block">
44+
<p><strong>Input:</strong> <span class="example-io">s = &quot;abcde&quot;, k = 1</span></p>
45+
46+
<p><strong>Output:</strong> <span class="example-io">15</span></p>
47+
48+
<p><strong>Explanation:</strong></p>
49+
50+
<p>All substrings are valid because every character appears at least once.</p>
51+
</div>
52+
53+
<p>&nbsp;</p>
54+
<p><strong>Constraints:</strong></p>
55+
56+
<ul>
57+
<li><code>1 &lt;= s.length &lt;= 3 * 10<sup>5</sup></code></li>
58+
<li><code>1 &lt;= k &lt;= s.length</code></li>
59+
<li><code>s</code> consists only of lowercase English letters.</li>
60+
</ul>
61+
62+
<!-- description:end -->
63+
64+
## 解法
65+
66+
<!-- solution:start -->
67+
68+
### 方法一:滑动窗口
69+
70+
我们可以枚举子字符串的右端点,然后用一个滑动窗口维护子字符串的左端点,使得滑动窗口内的子字符串中的每个字符出现次数都小于 $k$。
71+
72+
我们可以用一个数组 $\textit{cnt}$ 维护滑动窗口内的每个字符的出现次数,然后用一个变量 $\textit{l}$ 维护滑动窗口的左端点,用一个变量 $\textit{ans}$ 维护答案。
73+
74+
当我们枚举右端点时,我们可以将右端点的字符加入滑动窗口,然后判断滑动窗口内右端点的字符出现次数是否大于等于 $k$,如果是,则将左端点的字符移出滑动窗口,直到滑动窗口内的每个字符出现次数都小于 $k$。此时,对于左端点为 $[0, ..l - 1]$,且右端点为 $r$ 的子字符串,都满足题目要求,因此答案加上 $l$。
75+
76+
枚举结束后,返回答案即可。
77+
78+
时间复杂度 $O(n)$,其中 $n$ 为字符串 $s$ 的长度。空间复杂度 $O(|\Sigma|)$,其中 $\Sigma$ 是字符集,这里是小写字母集合,因此 $|\Sigma| = 26$。
79+
80+
<!-- tabs:start -->
81+
82+
#### Python3
83+
84+
```python
85+
class Solution:
86+
def numberOfSubstrings(self, s: str, k: int) -> int:
87+
cnt = Counter()
88+
ans = l = 0
89+
for c in s:
90+
cnt[c] += 1
91+
while cnt[c] >= k:
92+
cnt[s[l]] -= 1
93+
l += 1
94+
ans += l
95+
return ans
96+
```
97+
98+
#### Java
99+
100+
```java
101+
class Solution {
102+
public long numberOfSubstrings(String s, int k) {
103+
int[] cnt = new int[26];
104+
long ans = 0;
105+
for (int l = 0, r = 0; r < s.length(); ++r) {
106+
int c = s.charAt(r) - 'a';
107+
++cnt[c];
108+
while (cnt[c] >= k) {
109+
--cnt[s.charAt(l) - 'a'];
110+
l++;
111+
}
112+
ans += l;
113+
}
114+
return ans;
115+
}
116+
}
117+
```
118+
119+
#### C++
120+
121+
```cpp
122+
class Solution {
123+
public:
124+
long long numberOfSubstrings(string s, int k) {
125+
int n = s.size();
126+
long long ans = 0, l = 0;
127+
int cnt[26]{};
128+
for (char& c : s) {
129+
++cnt[c - 'a'];
130+
while (cnt[c - 'a'] >= k) {
131+
--cnt[s[l++] - 'a'];
132+
}
133+
ans += l;
134+
}
135+
return ans;
136+
}
137+
};
138+
```
139+
140+
#### Go
141+
142+
```go
143+
func numberOfSubstrings(s string, k int) (ans int64) {
144+
l := 0
145+
cnt := [26]int{}
146+
for _, c := range s {
147+
cnt[c-'a']++
148+
for cnt[c-'a'] >= k {
149+
cnt[s[l]-'a']--
150+
l++
151+
}
152+
ans += int64(l)
153+
}
154+
return
155+
}
156+
```
157+
158+
#### TypeScript
159+
160+
```ts
161+
function numberOfSubstrings(s: string, k: number): number {
162+
let [ans, l] = [0, 0];
163+
const cnt: number[] = Array(26).fill(0);
164+
for (const c of s) {
165+
const x = c.charCodeAt(0) - 97;
166+
++cnt[x];
167+
while (cnt[x] >= k) {
168+
--cnt[s[l++].charCodeAt(0) - 97];
169+
}
170+
ans += l;
171+
}
172+
return ans;
173+
}
174+
```
175+
176+
<!-- tabs:end -->
177+
178+
<!-- solution:end -->
179+
180+
<!-- problem:end -->
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
---
2+
comments: true
3+
difficulty: Hard
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3329.Count%20Substrings%20With%20K-Frequency%20Characters%20II/README_EN.md
5+
tags:
6+
- Sliding Window
7+
---
8+
9+
<!-- problem:start -->
10+
11+
# [3329. Count Substrings With K-Frequency Characters II 🔒](https://leetcode.com/problems/count-substrings-with-k-frequency-characters-ii)
12+
13+
[中文文档](/solution/3300-3399/3329.Count%20Substrings%20With%20K-Frequency%20Characters%20II/README.md)
14+
15+
## Description
16+
17+
<!-- description:start -->
18+
19+
<p>Given a string <code>s</code> and an integer <code>k</code>, return the total number of <span data-keyword="substring-nonempty">substrings</span> of <code>s</code> where <strong>at least one</strong> character appears <strong>at least</strong> <code>k</code> times.</p>
20+
21+
<p>&nbsp;</p>
22+
<p><strong class="example">Example 1:</strong></p>
23+
24+
<div class="example-block">
25+
<p><strong>Input:</strong> <span class="example-io">s = &quot;abacb&quot;, k = 2</span></p>
26+
27+
<p><strong>Output:</strong> <span class="example-io">4</span></p>
28+
29+
<p><strong>Explanation:</strong></p>
30+
31+
<p>The valid substrings are:</p>
32+
33+
<ul>
34+
<li>&quot;<code>aba&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
35+
<li><code>&quot;abac&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
36+
<li><code>&quot;abacb&quot;</code> (character <code>&#39;a&#39;</code> appears 2 times).</li>
37+
<li><code>&quot;bacb&quot;</code> (character <code>&#39;b&#39;</code> appears 2 times).</li>
38+
</ul>
39+
</div>
40+
41+
<p><strong class="example">Example 2:</strong></p>
42+
43+
<div class="example-block">
44+
<p><strong>Input:</strong> <span class="example-io">s = &quot;abcde&quot;, k = 1</span></p>
45+
46+
<p><strong>Output:</strong> <span class="example-io">15</span></p>
47+
48+
<p><strong>Explanation:</strong></p>
49+
50+
<p>All substrings are valid because every character appears at least once.</p>
51+
</div>
52+
53+
<p>&nbsp;</p>
54+
<p><strong>Constraints:</strong></p>
55+
56+
<ul>
57+
<li><code>1 &lt;= s.length &lt;= 3 * 10<sup>5</sup></code></li>
58+
<li><code>1 &lt;= k &lt;= s.length</code></li>
59+
<li><code>s</code> consists only of lowercase English letters.</li>
60+
</ul>
61+
62+
<!-- description:end -->
63+
64+
## Solutions
65+
66+
<!-- solution:start -->
67+
68+
### Solution 1: Sliding Window
69+
70+
We can enumerate the right endpoint of the substring, and then use a sliding window to maintain the left endpoint of the substring, ensuring that the occurrence count of each character in the sliding window is less than $k$.
71+
72+
We can use an array $\textit{cnt}$ to maintain the occurrence count of each character in the sliding window, then use a variable $\textit{l}$ to maintain the left endpoint of the sliding window, and use a variable $\textit{ans}$ to maintain the answer.
73+
74+
When we enumerate the right endpoint, we can add the character at the right endpoint to the sliding window, then check if the occurrence count of the character at the right endpoint in the sliding window is greater than or equal to $k$. If it is, we remove the character at the left endpoint from the sliding window until the occurrence count of each character in the sliding window is less than $k$. At this point, for substrings with left endpoints in the range $[0, ..l - 1]$ and right endpoint $r$, all satisfy the problem's requirements, so we add $l$ to the answer.
75+
76+
After enumeration, we return the answer.
77+
78+
The time complexity is $O(n)$, where $n$ is the length of the string $s$. The space complexity is $O(|\Sigma|)$, where $\Sigma$ is the character set, which in this case is the set of lowercase letters, so $|\Sigma| = 26$.
79+
80+
<!-- tabs:start -->
81+
82+
#### Python3
83+
84+
```python
85+
class Solution:
86+
def numberOfSubstrings(self, s: str, k: int) -> int:
87+
cnt = Counter()
88+
ans = l = 0
89+
for c in s:
90+
cnt[c] += 1
91+
while cnt[c] >= k:
92+
cnt[s[l]] -= 1
93+
l += 1
94+
ans += l
95+
return ans
96+
```
97+
98+
#### Java
99+
100+
```java
101+
class Solution {
102+
public long numberOfSubstrings(String s, int k) {
103+
int[] cnt = new int[26];
104+
long ans = 0;
105+
for (int l = 0, r = 0; r < s.length(); ++r) {
106+
int c = s.charAt(r) - 'a';
107+
++cnt[c];
108+
while (cnt[c] >= k) {
109+
--cnt[s.charAt(l) - 'a'];
110+
l++;
111+
}
112+
ans += l;
113+
}
114+
return ans;
115+
}
116+
}
117+
```
118+
119+
#### C++
120+
121+
```cpp
122+
class Solution {
123+
public:
124+
long long numberOfSubstrings(string s, int k) {
125+
int n = s.size();
126+
long long ans = 0, l = 0;
127+
int cnt[26]{};
128+
for (char& c : s) {
129+
++cnt[c - 'a'];
130+
while (cnt[c - 'a'] >= k) {
131+
--cnt[s[l++] - 'a'];
132+
}
133+
ans += l;
134+
}
135+
return ans;
136+
}
137+
};
138+
```
139+
140+
#### Go
141+
142+
```go
143+
func numberOfSubstrings(s string, k int) (ans int64) {
144+
l := 0
145+
cnt := [26]int{}
146+
for _, c := range s {
147+
cnt[c-'a']++
148+
for cnt[c-'a'] >= k {
149+
cnt[s[l]-'a']--
150+
l++
151+
}
152+
ans += int64(l)
153+
}
154+
return
155+
}
156+
```
157+
158+
#### TypeScript
159+
160+
```ts
161+
function numberOfSubstrings(s: string, k: number): number {
162+
let [ans, l] = [0, 0];
163+
const cnt: number[] = Array(26).fill(0);
164+
for (const c of s) {
165+
const x = c.charCodeAt(0) - 97;
166+
++cnt[x];
167+
while (cnt[x] >= k) {
168+
--cnt[s[l++].charCodeAt(0) - 97];
169+
}
170+
ans += l;
171+
}
172+
return ans;
173+
}
174+
```
175+
176+
<!-- tabs:end -->
177+
178+
<!-- solution:end -->
179+
180+
<!-- problem:end -->
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class Solution {
2+
public:
3+
long long numberOfSubstrings(string s, int k) {
4+
int n = s.size();
5+
long long ans = 0, l = 0;
6+
int cnt[26]{};
7+
for (char& c : s) {
8+
++cnt[c - 'a'];
9+
while (cnt[c - 'a'] >= k) {
10+
--cnt[s[l++] - 'a'];
11+
}
12+
ans += l;
13+
}
14+
return ans;
15+
}
16+
};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
func numberOfSubstrings(s string, k int) (ans int64) {
2+
l := 0
3+
cnt := [26]int{}
4+
for _, c := range s {
5+
cnt[c-'a']++
6+
for cnt[c-'a'] >= k {
7+
cnt[s[l]-'a']--
8+
l++
9+
}
10+
ans += int64(l)
11+
}
12+
return
13+
}

0 commit comments

Comments
 (0)