@@ -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