Skip to content

Commit 2d18cf7

Browse files
authored
feat: add solutions to lc problem: No.1593 (doocs#3889)
No.1593.Split a String Into the Max Number of Unique Substrings
1 parent 8d6b198 commit 2d18cf7

File tree

7 files changed

+294
-176
lines changed

7 files changed

+294
-176
lines changed

solution/1500-1599/1593.Split a String Into the Max Number of Unique Substrings/README.md

Lines changed: 102 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,17 @@ tags:
6868

6969
<!-- solution:start -->
7070

71-
### 方法一:DFS
71+
### 方法一:回溯 + 剪枝
7272

73-
经典 DFS 回溯问题。
73+
我们定义一个哈希表 $\textit{st}$,用于存储当前已经拆分出的子字符串。然后我们使用深度优先搜索的方式,尝试将字符串 $\textit{s}$ 拆分成若干个唯一的子字符串。
74+
75+
具体地,我们设计一个函数 $\text{dfs}(i)$,表示我们正在考虑将 $\textit{s}[i:]$ 进行拆分。
76+
77+
在函数 $\text{dfs}(i)$ 中,我们首先判断如果当前已经拆分出的子字符串的数量加上剩余的字符数小于等于当前的答案,那么我们就没有必要继续拆分,直接返回。如果 $i \geq n$,那么说明我们已经完成了对整个字符串的拆分,我们更新答案为当前的子字符串数量和答案的较大值。否则,我们枚举当前子字符串的结束位置 $j$(不包括 $j$),并判断 $\textit{s}[i..j)$ 是否已经被拆分出来。如果没有被拆分出来,我们将其加入到哈希表 $\textit{st}$ 中,并继续递归地考虑拆分剩余的部分。在递归调用结束后,我们需要将 $\textit{s}[i..j)$ 从哈希表 $\textit{st}$ 中移除。
78+
79+
最后,我们返回答案。
80+
81+
时间复杂度 $O(n^2 \times 2^n)$,空间复杂度 $O(n)$。其中 $n$ 为字符串 $\textit{s}$ 的长度。
7482

7583
<!-- tabs:start -->
7684

@@ -79,47 +87,52 @@ tags:
7987
```python
8088
class Solution:
8189
def maxUniqueSplit(self, s: str) -> int:
82-
def dfs(i, t):
90+
def dfs(i: int):
91+
nonlocal ans
92+
if len(st) + len(s) - i <= ans:
93+
return
8394
if i >= len(s):
84-
nonlocal ans
85-
ans = max(ans, t)
95+
ans = max(ans, len(st))
8696
return
8797
for j in range(i + 1, len(s) + 1):
88-
if s[i:j] not in vis:
89-
vis.add(s[i:j])
90-
dfs(j, t + 1)
91-
vis.remove(s[i:j])
92-
93-
vis = set()
94-
ans = 1
95-
dfs(0, 0)
98+
if s[i:j] not in st:
99+
st.add(s[i:j])
100+
dfs(j)
101+
st.remove(s[i:j])
102+
103+
ans = 0
104+
st = set()
105+
dfs(0)
96106
return ans
97107
```
98108

99109
#### Java
100110

101111
```java
102112
class Solution {
103-
private Set<String> vis = new HashSet<>();
104-
private int ans = 1;
113+
private Set<String> st = new HashSet<>();
114+
private int ans;
105115
private String s;
106116

107117
public int maxUniqueSplit(String s) {
108118
this.s = s;
109-
dfs(0, 0);
119+
dfs(0);
110120
return ans;
111121
}
112122

113-
private void dfs(int i, int t) {
123+
private void dfs(int i) {
124+
if (st.size() + s.length() - i <= ans) {
125+
return;
126+
}
114127
if (i >= s.length()) {
115-
ans = Math.max(ans, t);
128+
ans = Math.max(ans, st.size());
116129
return;
117130
}
118131
for (int j = i + 1; j <= s.length(); ++j) {
119-
String x = s.substring(i, j);
120-
if (vis.add(x)) {
121-
dfs(j, t + 1);
122-
vis.remove(x);
132+
String t = s.substring(i, j);
133+
if (st.add(t)) {
134+
dfs(j);
135+
st.remove(t);
123136
}
124137
}
125138
}
@@ -131,57 +144,87 @@ class Solution {
131144
```cpp
132145
class Solution {
133146
public:
134-
unordered_set<string> vis;
135-
string s;
136-
int ans = 1;
137-
138147
int maxUniqueSplit(string s) {
139-
this->s = s;
140-
dfs(0, 0);
141-
return ans;
142-
}
143-
144-
void dfs(int i, int t) {
145-
if (i >= s.size()) {
146-
ans = max(ans, t);
147-
return;
148-
}
149-
for (int j = i + 1; j <= s.size(); ++j) {
150-
string x = s.substr(i, j - i);
151-
if (!vis.count(x)) {
152-
vis.insert(x);
153-
dfs(j, t + 1);
154-
vis.erase(x);
148+
unordered_set<string> st;
149+
int n = s.size();
150+
int ans = 0;
151+
auto dfs = [&](this auto&& dfs, int i) -> void {
152+
if (st.size() + n - i <= ans) {
153+
return;
155154
}
156-
}
155+
if (i >= n) {
156+
ans = max(ans, (int) st.size());
157+
return;
158+
}
159+
for (int j = i + 1; j <= n; ++j) {
160+
string t = s.substr(i, j - i);
161+
if (!st.contains(t)) {
162+
st.insert(t);
163+
dfs(j);
164+
st.erase(t);
165+
}
166+
}
167+
};
168+
dfs(0);
169+
return ans;
157170
}
158171
};
159172
```
160173
161174
#### Go
162175
163176
```go
164-
func maxUniqueSplit(s string) int {
165-
ans := 1
166-
vis := map[string]bool{}
167-
168-
var dfs func(i, t int)
169-
dfs = func(i, t int) {
170-
if i >= len(s) {
171-
ans = max(ans, t)
177+
func maxUniqueSplit(s string) (ans int) {
178+
st := map[string]bool{}
179+
n := len(s)
180+
var dfs func(int)
181+
dfs = func(i int) {
182+
if len(st)+n-i <= ans {
183+
return
184+
}
185+
if i >= n {
186+
ans = max(ans, len(st))
172187
return
173188
}
174-
for j := i + 1; j <= len(s); j++ {
175-
x := s[i:j]
176-
if !vis[x] {
177-
vis[x] = true
178-
dfs(j, t+1)
179-
vis[x] = false
189+
for j := i + 1; j <= n; j++ {
190+
if t := s[i:j]; !st[t] {
191+
st[t] = true
192+
dfs(j)
193+
delete(st, t)
180194
}
181195
}
182196
}
183-
dfs(0, 0)
184-
return ans
197+
dfs(0)
198+
return
199+
}
200+
```
201+
202+
#### TypeScript
203+
204+
```ts
205+
function maxUniqueSplit(s: string): number {
206+
const n = s.length;
207+
const st = new Set<string>();
208+
let ans = 0;
209+
const dfs = (i: number): void => {
210+
if (st.size + n - i <= ans) {
211+
return;
212+
}
213+
if (i >= n) {
214+
ans = Math.max(ans, st.size);
215+
return;
216+
}
217+
for (let j = i + 1; j <= n; ++j) {
218+
const t = s.slice(i, j);
219+
if (!st.has(t)) {
220+
st.add(t);
221+
dfs(j);
222+
st.delete(t);
223+
}
224+
}
225+
};
226+
dfs(0);
227+
return ans;
185228
}
186229
```
187230

0 commit comments

Comments
 (0)