
题目描述
给你一个字符串 s
,按照以下步骤将其分割为 互不相同的段 :
- 从下标 0 开始构建一个段。
- 逐字符扩展当前段,直到该段之前未曾出现过。
- 只要当前段是唯一的,就将其加入段列表,标记为已经出现过,并从下一个下标开始构建新的段。
- 重复上述步骤,直到处理完整个字符串
s
。
返回字符串数组 segments
,其中 segments[i]
表示创建的第 i
段。
示例 1:
输入: s = "abbccccd"
输出: ["a","b","bc","c","cc","d"]
解释:
下标 |
添加后的段 |
已经出现过的段 |
当前段是否已经出现过? |
新段 |
更新后已经出现过的段 |
0 |
"a" |
[] |
否 |
"" |
["a"] |
1 |
"b" |
["a"] |
否 |
"" |
["a", "b"] |
2 |
"b" |
["a", "b"] |
是 |
"b" |
["a", "b"] |
3 |
"bc" |
["a", "b"] |
否 |
"" |
["a", "b", "bc"] |
4 |
"c" |
["a", "b", "bc"] |
否 |
"" |
["a", "b", "bc", "c"] |
5 |
"c" |
["a", "b", "bc", "c"] |
是 |
"c" |
["a", "b", "bc", "c"] |
6 |
"cc" |
["a", "b", "bc", "c"] |
否 |
"" |
["a", "b", "bc", "c", "cc"] |
7 |
"d" |
["a", "b", "bc", "c", "cc"] |
否 |
"" |
["a", "b", "bc", "c", "cc", "d"] |
因此,最终输出为 ["a", "b", "bc", "c", "cc", "d"]
。
示例 2:
输入: s = "aaaa"
输出: ["a","aa"]
解释:
下标 |
添加后的段 |
已经出现过的段 |
当前段是否已经出现过? |
新段 |
更新后已经出现过的段 |
0 |
"a" |
[] |
否 |
"" |
["a"] |
1 |
"a" |
["a"] |
是 |
"a" |
["a"] |
2 |
"aa" |
["a"] |
否 |
"" |
["a", "aa"] |
3 |
"a" |
["a", "aa"] |
是 |
"a" |
["a", "aa"] |
因此,最终输出为 ["a", "aa"]
。
提示:
1 <= s.length <= 105
s
仅包含小写英文字母。
解法
方法一:哈希表 + 模拟
我们可以用一个哈希表 \(\textit{vis}\) 来记录已经出现过的段。然后我们遍历字符串 \(s\),逐字符构建当前段 \(t\),直到该段之前未曾出现过。每当我们构建出一个新的段时,就将其加入到结果列表中,并将其标记为已经出现过。
遍历结束后,返回结果列表即可。
时间复杂度 \(O(n \times \sqrt{n})\),空间复杂度 \(O(n)\),其中 \(n\) 是字符串 \(s\) 的长度。
方法二:字符串哈希 + 哈希表 + 模拟
我们可以使用字符串哈希来加速段的查找。具体地,我们可以为每个段计算一个哈希值,并将其存储在一个哈希表中。这样,我们就可以在常数时间内判断一个段是否已经出现过。
具体地,我们首先根据字符串 \(s\) 创建一个字符串哈希类 \(\textit{Hashing}\),该类支持计算字符串的哈希值。然后,我们遍历字符串 \(s\),用两个指针 \(l\) 和 \(r\) 来表示当前段的起始和结束位置(下标从 \(1\) 开始)。每次扩展 \(r\),我们计算当前段的哈希值 \(x\),如果该哈希值不在哈希表中,则将其加入结果列表,并将其哈希值标记为已经出现过。否则,我们继续扩展 \(r\),直到找到一个新的段。
遍历结束后,返回结果列表即可。
时间复杂度 \(O(n)\),空间复杂度 \(O(n)\),其中 \(n\) 是字符串 \(s\) 的长度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | class Hashing:
__slots__ = ["mod", "h", "p"]
def __init__(
self, s: Union[str, List[str]], base: int = 13331, mod: int = 998244353
):
self.mod = mod
self.h = [0] * (len(s) + 1)
self.p = [1] * (len(s) + 1)
for i in range(1, len(s) + 1):
self.h[i] = (self.h[i - 1] * base + ord(s[i - 1])) % mod
self.p[i] = (self.p[i - 1] * base) % mod
def query(self, l: int, r: int) -> int:
return (self.h[r] - self.h[l - 1] * self.p[r - l + 1]) % self.mod
class Solution:
def partitionString(self, s: str) -> List[str]:
hashing = Hashing(s)
vis = set()
l = 1
ans = []
for r, c in enumerate(s, 1):
x = hashing.query(l, r)
if x not in vis:
vis.add(x)
ans.append(s[l - 1 : r])
l = r + 1
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | class Hashing {
private final long[] p;
private final long[] h;
private final long mod;
public Hashing(String word) {
this(word, 13331, 998244353);
}
public Hashing(String word, long base, int mod) {
int n = word.length();
p = new long[n + 1];
h = new long[n + 1];
p[0] = 1;
this.mod = mod;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * base % mod;
h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
}
}
public long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
}
class Solution {
public List<String> partitionString(String s) {
Hashing hashing = new Hashing(s);
Set<Long> vis = new HashSet<>();
List<String> ans = new ArrayList<>();
for (int l = 1, r = 1; r <= s.length(); ++r) {
long x = hashing.query(l, r);
if (vis.add(x)) {
ans.add(s.substring(l - 1, r));
l = r + 1;
}
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 | class Hashing {
private:
vector<long long> p;
vector<long long> h;
long long mod;
public:
Hashing(const string& word, long long base = 13331, long long mod = 998244353) {
int n = word.size();
p.resize(n + 1);
h.resize(n + 1);
p[0] = 1;
this->mod = mod;
for (int i = 1; i <= n; i++) {
p[i] = (p[i - 1] * base) % mod;
h[i] = (h[i - 1] * base + word[i - 1]) % mod;
}
}
long long query(int l, int r) const {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
};
class Solution {
public:
vector<string> partitionString(const string& s) {
Hashing hashing(s);
unordered_set<long long> vis;
vector<string> ans;
int l = 1;
for (int r = 1; r <= (int) s.size(); ++r) {
long long x = hashing.query(l, r);
if (!vis.contains(x)) {
vis.insert(x);
ans.push_back(s.substr(l - 1, r - l + 1));
l = r + 1;
}
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | type Hashing struct {
p, h []int64
mod int64
}
func NewHashing(s string, base, mod int64) *Hashing {
n := len(s)
p := make([]int64, n+1)
h := make([]int64, n+1)
p[0] = 1
for i := 1; i <= n; i++ {
p[i] = p[i-1] * base % mod
h[i] = (h[i-1]*base + int64(s[i-1])) % mod
}
return &Hashing{p, h, mod}
}
func (hs *Hashing) Query(l, r int) int64 {
return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
}
func partitionString(s string) (ans []string) {
n := len(s)
hashing := NewHashing(s, 13331, 998244353)
vis := make(map[int64]bool)
l := 1
for r := 1; r <= n; r++ {
x := hashing.Query(l, r)
if !vis[x] {
vis[x] = true
ans = append(ans, s[l-1:r])
l = r + 1
}
}
return
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | class Hashing {
private p: bigint[];
private h: bigint[];
private mod: bigint;
constructor(s: string, base: bigint = 13331n, mod: bigint = 998244353n) {
const n = s.length;
this.mod = mod;
this.p = new Array<bigint>(n + 1).fill(1n);
this.h = new Array<bigint>(n + 1).fill(0n);
for (let i = 1; i <= n; i++) {
this.p[i] = (this.p[i - 1] * base) % mod;
this.h[i] = (this.h[i - 1] * base + BigInt(s.charCodeAt(i - 1))) % mod;
}
}
query(l: number, r: number): bigint {
return (this.h[r] - ((this.h[l - 1] * this.p[r - l + 1]) % this.mod) + this.mod) % this.mod;
}
}
function partitionString(s: string): string[] {
const n = s.length;
const hashing = new Hashing(s);
const vis = new Set<string>();
const ans: string[] = [];
let l = 1;
for (let r = 1; r <= n; r++) {
const x = hashing.query(l, r).toString();
if (!vis.has(x)) {
vis.add(x);
ans.push(s.slice(l - 1, r));
l = r + 1;
}
}
return ans;
}
|