题目描述
给你一个下标从 0 开始的字符串 word
和一个整数 k
。
在每一秒,你必须执行以下操作:
- 移除
word
的前 k
个字符。
- 在
word
的末尾添加 k
个任意字符。
注意 添加的字符不必和移除的字符相同。但是,必须在每一秒钟都执行 两种 操作。
返回将 word
恢复到其 初始 状态所需的 最短 时间(该时间必须大于零)。
示例 1:
输入:word = "abacaba", k = 3
输出:2
解释:
第 1 秒,移除 word 的前缀 "aba",并在末尾添加 "bac" 。因此,word 变为 "cababac"。
第 2 秒,移除 word 的前缀 "cab",并在末尾添加 "aba" 。因此,word 变为 "abacaba" 并恢复到始状态。
可以证明,2 秒是 word 恢复到其初始状态所需的最短时间。
示例 2:
输入:word = "abacaba", k = 4
输出:1
解释:
第 1 秒,移除 word 的前缀 "abac",并在末尾添加 "caba" 。因此,word 变为 "abacaba" 并恢复到初始状态。
可以证明,1 秒是 word 恢复到其初始状态所需的最短时间。
示例 3:
输入:word = "abcbabcd", k = 2
输出:4
解释:
每一秒,我们都移除 word 的前 2 个字符,并在 word 末尾添加相同的字符。
4 秒后,word 变为 "abcbabcd" 并恢复到初始状态。
可以证明,4 秒是 word 恢复到其初始状态所需的最短时间。
提示:
1 <= word.length <= 106
1 <= k <= word.length
word
仅由小写英文字母组成。
解法
方法一:枚举 + 字符串哈希
我们不妨假设,如果只操作一次,就能使得 word
恢复到初始状态,那么意味着 word[k:]
是 word
的前缀,即 word[k:] == word[:n-k]
。
如果有多次操作,不妨设 $i$ 为操作次数,那么意味着 word[k*i:]
是 word
的前缀,即 word[k*i:] == word[:n-k*i]
。
因此,我们可以枚举操作次数,利用字符串哈希来判断两个字符串是否相等。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为 word
的长度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Hashing:
__slots__ = ["mod", "h", "p"]
def __init__(self, s: str, base: int, mod: int):
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 minimumTimeToInitialState(self, word: str, k: int) -> int:
hashing = Hashing(word, 13331, 998244353)
n = len(word)
for i in range(k, n, k):
if hashing.query(1, n - i) == hashing.query(i + 1, n):
return i // k
return (n + k - 1) // k
|
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 | class Hashing {
private final long[] p;
private final long[] h;
private final long mod;
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) - 'a') % mod;
}
}
public long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
}
class Solution {
public int minimumTimeToInitialState(String word, int k) {
Hashing hashing = new Hashing(word, 13331, 998244353);
int n = word.length();
for (int i = k; i < n; i += k) {
if (hashing.query(1, n - i) == hashing.query(i + 1, n)) {
return i / k;
}
}
return (n + k - 1) / k;
}
}
|
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:
vector<long long> p;
vector<long long> h;
long long mod;
public:
Hashing(string word, long long base, int mod) {
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] - 'a') % mod;
}
}
long long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
};
class Solution {
public:
int minimumTimeToInitialState(string word, int k) {
Hashing hashing(word, 13331, 998244353);
int n = word.size();
for (int i = k; i < n; i += k) {
if (hashing.query(1, n - i) == hashing.query(i + 1, n)) {
return i / k;
}
}
return (n + k - 1) / k;
}
};
|
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 | type Hashing struct {
p []int64
h []int64
mod int64
}
func NewHashing(word string, base int64, mod int64) *Hashing {
n := len(word)
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(word[i-1]-'a')) % mod
}
return &Hashing{p, h, mod}
}
func (hashing *Hashing) Query(l, r int) int64 {
return (hashing.h[r] - hashing.h[l-1]*hashing.p[r-l+1]%hashing.mod + hashing.mod) % hashing.mod
}
func minimumTimeToInitialState(word string, k int) int {
hashing := NewHashing(word, 13331, 998244353)
n := len(word)
for i := k; i < n; i += k {
if hashing.Query(1, n-i) == hashing.Query(i+1, n) {
return i / k
}
}
return (n + k - 1) / k
}
|