Skip to content

Commit 8f706c5

Browse files
authored
feat: add solutions to lc problem: No.3144 (doocs#2810)
No.3144.Minimum Substring Partition of Equal Character Frequency
1 parent 2e542d1 commit 8f706c5

File tree

7 files changed

+517
-8
lines changed

7 files changed

+517
-8
lines changed

solution/3100-3199/3144.Minimum Substring Partition of Equal Character Frequency/README.md

+178-4
Original file line numberDiff line numberDiff line change
@@ -51,24 +51,198 @@
5151

5252
## 解法
5353

54-
### 方法一
54+
### 方法一:记忆化搜索 + 哈希表
55+
56+
我们设计一个函数 $\text{dfs}(i)$,表示从字符串 $s[i]$ 开始分割的最少子字符串数量。那么答案就是 $\text{dfs}(0)$。
57+
58+
函数 $\text{dfs}(i)$ 的计算过程如下:
59+
60+
如果 $i \geq n$,表示已经处理完了所有字符,返回 $0$。
61+
62+
否则,我们维护一个哈希表 $\text{cnt}$,表示当前子字符串中每个字符出现的次数。另外,我们还维护一个哈希表 $\text{freq}$,表示每个字符出现的次数的频率。
63+
64+
然后我们枚举 $j$ 从 $i$ 到 $n-1$,表示当前子字符串的结束位置。对于每个 $j$,我们更新 $\text{cnt}$ 和 $\text{freq}$,然后判断 $\text{freq}$ 的大小是否为 $1$,如果是的话,我们可以从 $j+1$ 开始分割,此时答案为 $1 + \text{dfs}(j+1)$,我们取所有 $j$ 中答案的最小值作为函数的返回值。
65+
66+
为了避免重复计算,我们使用记忆化搜索。
67+
68+
时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为字符串 $s$ 的长度。
5569

5670
<!-- tabs:start -->
5771

5872
```python
59-
73+
class Solution:
74+
def minimumSubstringsInPartition(self, s: str) -> int:
75+
@cache
76+
def dfs(i: int) -> int:
77+
if i >= n:
78+
return 0
79+
cnt = defaultdict(int)
80+
freq = defaultdict(int)
81+
ans = n - i
82+
for j in range(i, n):
83+
if cnt[s[j]]:
84+
freq[cnt[s[j]]] -= 1
85+
if not freq[cnt[s[j]]]:
86+
freq.pop(cnt[s[j]])
87+
cnt[s[j]] += 1
88+
freq[cnt[s[j]]] += 1
89+
if len(freq) == 1 and (t := 1 + dfs(j + 1)) < ans:
90+
ans = t
91+
return ans
92+
93+
n = len(s)
94+
return dfs(0)
6095
```
6196

6297
```java
63-
98+
class Solution {
99+
private int n;
100+
private char[] s;
101+
private Integer[] f;
102+
103+
public int minimumSubstringsInPartition(String s) {
104+
n = s.length();
105+
f = new Integer[n];
106+
this.s = s.toCharArray();
107+
return dfs(0);
108+
}
109+
110+
private int dfs(int i) {
111+
if (i >= n) {
112+
return 0;
113+
}
114+
if (f[i] != null) {
115+
return f[i];
116+
}
117+
int[] cnt = new int[26];
118+
Map<Integer, Integer> freq = new HashMap<>(26);
119+
int ans = n - i;
120+
for (int j = i; j < n; ++j) {
121+
int k = s[j] - 'a';
122+
if (cnt[k] > 0) {
123+
if (freq.merge(cnt[k], -1, Integer::sum) == 0) {
124+
freq.remove(cnt[k]);
125+
}
126+
}
127+
++cnt[k];
128+
freq.merge(cnt[k], 1, Integer::sum);
129+
if (freq.size() == 1) {
130+
ans = Math.min(ans, 1 + dfs(j + 1));
131+
}
132+
}
133+
return f[i] = ans;
134+
}
135+
}
64136
```
65137

66138
```cpp
67-
139+
class Solution {
140+
public:
141+
int minimumSubstringsInPartition(string s) {
142+
int n = s.size();
143+
int f[n];
144+
memset(f, -1, sizeof(f));
145+
function<int(int)> dfs = [&](int i) {
146+
if (i >= n) {
147+
return 0;
148+
}
149+
if (f[i] != -1) {
150+
return f[i];
151+
}
152+
f[i] = n - i;
153+
int cnt[26]{};
154+
unordered_map<int, int> freq;
155+
for (int j = i; j < n; ++j) {
156+
int k = s[j] - 'a';
157+
if (cnt[k]) {
158+
freq[cnt[k]]--;
159+
if (freq[cnt[k]] == 0) {
160+
freq.erase(cnt[k]);
161+
}
162+
}
163+
++cnt[k];
164+
++freq[cnt[k]];
165+
if (freq.size() == 1) {
166+
f[i] = min(f[i], 1 + dfs(j + 1));
167+
}
168+
}
169+
return f[i];
170+
};
171+
return dfs(0);
172+
}
173+
};
68174
```
69175
70176
```go
177+
func minimumSubstringsInPartition(s string) int {
178+
n := len(s)
179+
f := make([]int, n)
180+
for i := range f {
181+
f[i] = -1
182+
}
183+
var dfs func(int) int
184+
dfs = func(i int) int {
185+
if i >= n {
186+
return 0
187+
}
188+
if f[i] != -1 {
189+
return f[i]
190+
}
191+
cnt := [26]int{}
192+
freq := map[int]int{}
193+
f[i] = n - i
194+
for j := i; j < n; j++ {
195+
k := int(s[j] - 'a')
196+
if cnt[k] > 0 {
197+
freq[cnt[k]]--
198+
if freq[cnt[k]] == 0 {
199+
delete(freq, cnt[k])
200+
}
201+
}
202+
cnt[k]++
203+
freq[cnt[k]]++
204+
if len(freq) == 1 {
205+
f[i] = min(f[i], 1+dfs(j+1))
206+
}
207+
}
208+
return f[i]
209+
}
210+
return dfs(0)
211+
}
212+
```
71213

214+
```ts
215+
function minimumSubstringsInPartition(s: string): number {
216+
const n = s.length;
217+
const f: number[] = Array(n).fill(-1);
218+
const dfs = (i: number): number => {
219+
if (i >= n) {
220+
return 0;
221+
}
222+
if (f[i] !== -1) {
223+
return f[i];
224+
}
225+
const cnt: Map<number, number> = new Map();
226+
const freq: Map<number, number> = new Map();
227+
f[i] = n - i;
228+
for (let j = i; j < n; ++j) {
229+
const k = s.charCodeAt(j) - 97;
230+
if (freq.has(cnt.get(k)!)) {
231+
freq.set(cnt.get(k)!, freq.get(cnt.get(k)!)! - 1);
232+
if (freq.get(cnt.get(k)!) === 0) {
233+
freq.delete(cnt.get(k)!);
234+
}
235+
}
236+
cnt.set(k, (cnt.get(k) || 0) + 1);
237+
freq.set(cnt.get(k)!, (freq.get(cnt.get(k)!) || 0) + 1);
238+
if (freq.size === 1) {
239+
f[i] = Math.min(f[i], 1 + dfs(j + 1));
240+
}
241+
}
242+
return f[i];
243+
};
244+
return dfs(0);
245+
}
72246
```
73247

74248
<!-- tabs:end -->

0 commit comments

Comments
 (0)