@@ -188,32 +188,339 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3500-3599/3597.Pa
188
188
189
189
<!-- solution:start -->
190
190
191
- ### 方法一
191
+ ### 方法一:哈希表 + 模拟
192
+
193
+ 我们可以用一个哈希表 $\textit{vis}$ 来记录已经出现过的段。然后我们遍历字符串 $s$,逐字符构建当前段 $t$,直到该段之前未曾出现过。每当我们构建出一个新的段时,就将其加入到结果列表中,并将其标记为已经出现过。
194
+
195
+ 遍历结束后,返回结果列表即可。
196
+
197
+ 时间复杂度 $O(n \times \sqrt{n})$,空间复杂度 $O(n)$,其中 $n$ 是字符串 $s$ 的长度。
192
198
193
199
<!-- tabs:start -->
194
200
195
201
#### Python3
196
202
197
203
```python
198
-
204
+ class Solution:
205
+ def partitionString(self, s: str) -> List[str]:
206
+ vis = set()
207
+ ans = []
208
+ t = ""
209
+ for c in s:
210
+ t += c
211
+ if t not in vis:
212
+ vis.add(t)
213
+ ans.append(t)
214
+ t = ""
215
+ return ans
199
216
```
200
217
201
218
#### Java
202
219
203
220
```java
204
-
221
+ class Solution {
222
+ public List<String> partitionString(String s) {
223
+ Set<String> vis = new HashSet<>();
224
+ List<String> ans = new ArrayList<>();
225
+ String t = "";
226
+ for (char c : s.toCharArray()) {
227
+ t += c;
228
+ if (vis.add(t)) {
229
+ ans.add(t);
230
+ t = "";
231
+ }
232
+ }
233
+ return ans;
234
+ }
235
+ }
205
236
```
206
237
207
238
#### C++
208
239
209
240
```cpp
241
+ class Solution {
242
+ public:
243
+ vector<string> partitionString(string s) {
244
+ unordered_set<string> vis;
245
+ vector<string> ans;
246
+ string t = "";
247
+ for (char c : s) {
248
+ t += c;
249
+ if (!vis.contains(t)) {
250
+ vis.insert(t);
251
+ ans.push_back(t);
252
+ t = "";
253
+ }
254
+ }
255
+ return ans;
256
+ }
257
+ };
258
+ ```
259
+
260
+ #### Go
261
+
262
+ ```go
263
+ func partitionString(s string) (ans []string) {
264
+ vis := make(map[string]bool)
265
+ t := ""
266
+ for _, c := range s {
267
+ t += string(c)
268
+ if !vis[t] {
269
+ vis[t] = true
270
+ ans = append(ans, t)
271
+ t = ""
272
+ }
273
+ }
274
+ return
275
+ }
276
+ ```
277
+
278
+ #### TypeScript
279
+
280
+ ```ts
281
+ function partitionString(s: string): string[] {
282
+ const vis = new Set<string>();
283
+ const ans: string[] = [];
284
+ let t = '';
285
+ for (const c of s) {
286
+ t += c;
287
+ if (!vis.has(t)) {
288
+ vis.add(t);
289
+ ans.push(t);
290
+ t = '';
291
+ }
292
+ }
293
+ return ans;
294
+ }
295
+ ```
296
+
297
+ <!-- tabs:end -->
298
+
299
+ <!-- solution:end -->
300
+
301
+ <!-- solution:start -->
302
+
303
+ ### 方法二:字符串哈希 + 哈希表 + 模拟
210
304
305
+ 我们可以使用字符串哈希来加速段的查找。具体地,我们可以为每个段计算一个哈希值,并将其存储在一个哈希表中。这样,我们就可以在常数时间内判断一个段是否已经出现过。
306
+
307
+ 具体地,我们首先根据字符串 $s$ 创建一个字符串哈希类 $\textit{Hashing}$,该类支持计算字符串的哈希值。然后,我们遍历字符串 $s$,用两个指针 $l$ 和 $r$ 来表示当前段的起始和结束位置(下标从 $1$ 开始)。每次扩展 $r$,我们计算当前段的哈希值 $x$,如果该哈希值不在哈希表中,则将其加入结果列表,并将其哈希值标记为已经出现过。否则,我们继续扩展 $r$,直到找到一个新的段。
308
+
309
+ 遍历结束后,返回结果列表即可。
310
+
311
+ 时间复杂度 $O(n)$,空间复杂度 $O(n)$,其中 $n$ 是字符串 $s$ 的长度。
312
+
313
+ <!-- tabs:start -->
314
+
315
+ #### Python3
316
+
317
+ ```python
318
+ class Hashing:
319
+ __slots__ = ["mod", "h", "p"]
320
+
321
+ def __init__(
322
+ self, s: Union[str, List[str]], base: int = 13331, mod: int = 998244353
323
+ ):
324
+ self.mod = mod
325
+ self.h = [0] * (len(s) + 1)
326
+ self.p = [1] * (len(s) + 1)
327
+ for i in range(1, len(s) + 1):
328
+ self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod
329
+ self.p[i] = (self.p[i - 1] * base) % mod
330
+
331
+ def query(self, l: int, r: int) -> int:
332
+ return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod
333
+
334
+
335
+ class Solution:
336
+ def partitionString(self, s: str) -> List[str]:
337
+ hashing = Hashing(s)
338
+ vis = set()
339
+ l = 1
340
+ ans = []
341
+ for r, c in enumerate(s, 1):
342
+ x = hashing.query(l, r)
343
+ if x not in vis:
344
+ vis.add(x)
345
+ ans.append(s[l - 1 : r])
346
+ l = r + 1
347
+ return ans
348
+ ```
349
+
350
+ #### Java
351
+
352
+ ```java
353
+ class Hashing {
354
+ private final long[] p;
355
+ private final long[] h;
356
+ private final long mod;
357
+
358
+ public Hashing(String word) {
359
+ this(word, 13331, 998244353);
360
+ }
361
+
362
+ public Hashing(String word, long base, int mod) {
363
+ int n = word.length();
364
+ p = new long[n + 1];
365
+ h = new long[n + 1];
366
+ p[0] = 1;
367
+ this.mod = mod;
368
+ for (int i = 1; i <= n; i++) {
369
+ p[i] = p[i - 1] * base % mod;
370
+ h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
371
+ }
372
+ }
373
+
374
+ public long query(int l, int r) {
375
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
376
+ }
377
+ }
378
+
379
+ class Solution {
380
+ public List<String> partitionString(String s) {
381
+ Hashing hashing = new Hashing(s);
382
+ Set<Long> vis = new HashSet<>();
383
+ List<String> ans = new ArrayList<>();
384
+ for (int l = 1, r = 1; r <= s.length(); ++r) {
385
+ long x = hashing.query(l, r);
386
+ if (vis.add(x)) {
387
+ ans.add(s.substring(l - 1, r));
388
+ l = r + 1;
389
+ }
390
+ }
391
+ return ans;
392
+ }
393
+ }
394
+ ```
395
+
396
+ #### C++
397
+
398
+ ```cpp
399
+ class Hashing {
400
+ private:
401
+ vector<long long> p;
402
+ vector<long long> h;
403
+ long long mod;
404
+
405
+ public:
406
+ Hashing(const string& word, long long base = 13331, long long mod = 998244353) {
407
+ int n = word.size();
408
+ p.resize(n + 1);
409
+ h.resize(n + 1);
410
+ p[0] = 1;
411
+ this->mod = mod;
412
+ for (int i = 1; i <= n; i++) {
413
+ p[i] = (p[i - 1] * base) % mod;
414
+ h[i] = (h[i - 1] * base + word[i - 1]) % mod;
415
+ }
416
+ }
417
+
418
+ long long query(int l, int r) const {
419
+ return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
420
+ }
421
+ };
422
+
423
+ class Solution {
424
+ public:
425
+ vector<string> partitionString(const string& s) {
426
+ Hashing hashing(s);
427
+ unordered_set<long long> vis;
428
+ vector<string> ans;
429
+ int l = 1;
430
+ for (int r = 1; r <= (int) s.size(); ++r) {
431
+ long long x = hashing.query(l, r);
432
+ if (!vis.contains(x)) {
433
+ vis.insert(x);
434
+ ans.push_back(s.substr(l - 1, r - l + 1));
435
+ l = r + 1;
436
+ }
437
+ }
438
+ return ans;
439
+ }
440
+ };
211
441
```
212
442
213
443
#### Go
214
444
215
445
```go
446
+ type Hashing struct {
447
+ p, h []int64
448
+ mod int64
449
+ }
450
+
451
+ func NewHashing(s string, base, mod int64) *Hashing {
452
+ n := len(s)
453
+ p := make([]int64, n+1)
454
+ h := make([]int64, n+1)
455
+ p[0] = 1
456
+ for i := 1; i <= n; i++ {
457
+ p[i] = p[i-1] * base % mod
458
+ h[i] = (h[i-1]*base + int64(s[i-1])) % mod
459
+ }
460
+ return &Hashing{p, h, mod}
461
+ }
462
+
463
+ func (hs *Hashing) Query(l, r int) int64 {
464
+ return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
465
+ }
466
+
467
+ func partitionString(s string) (ans []string) {
468
+ n := len(s)
469
+ hashing := NewHashing(s, 13331, 998244353)
470
+ vis := make(map[int64]bool)
471
+ l := 1
472
+ for r := 1; r <= n; r++ {
473
+ x := hashing.Query(l, r)
474
+ if !vis[x] {
475
+ vis[x] = true
476
+ ans = append(ans, s[l-1:r])
477
+ l = r + 1
478
+ }
479
+ }
480
+ return
481
+ }
482
+ ```
216
483
484
+ #### TypeScript
485
+
486
+ ```ts
487
+ class Hashing {
488
+ private p: bigint[];
489
+ private h: bigint[];
490
+ private mod: bigint;
491
+
492
+ constructor(s: string, base: bigint = 13331n, mod: bigint = 998244353n) {
493
+ const n = s.length;
494
+ this.mod = mod;
495
+ this.p = new Array<bigint>(n + 1).fill(1n);
496
+ this.h = new Array<bigint>(n + 1).fill(0n);
497
+ for (let i = 1; i <= n; i++) {
498
+ this.p[i] = (this.p[i - 1] * base) % mod;
499
+ this.h[i] = (this.h[i - 1] * base + BigInt(s.charCodeAt(i - 1))) % mod;
500
+ }
501
+ }
502
+
503
+ query(l: number, r: number): bigint {
504
+ return (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % this.mod;
505
+ }
506
+ }
507
+
508
+ function partitionString(s: string): string[] {
509
+ const n = s.length;
510
+ const hashing = new Hashing(s);
511
+ const vis = new Set<string>();
512
+ const ans: string[] = [];
513
+ let l = 1;
514
+ for (let r = 1; r <= n; r++) {
515
+ const x = hashing.query(l, r).toString();
516
+ if (!vis.has(x)) {
517
+ vis.add(x);
518
+ ans.push(s.slice(l - 1, r));
519
+ l = r + 1;
520
+ }
521
+ }
522
+ return ans;
523
+ }
217
524
```
218
525
219
526
<!-- tabs:end -->
0 commit comments