题目描述
给你一个二进制字符串 s
,你需要将字符串分割成一个或者多个 子字符串 ,使每个子字符串都是 美丽 的。
如果一个字符串满足以下条件,我们称它是 美丽 的:
- 它不包含前导 0 。
- 它是
5
的幂的 二进制 表示。
请你返回分割后的子字符串的 最少 数目。如果无法将字符串 s
分割成美丽子字符串,请你返回 -1
。
子字符串是一个字符串中一段连续的字符序列。
示例 1:
输入:s = "1011"
输出:2
解释:我们可以将输入字符串分成 ["101", "1"] 。
- 字符串 "101" 不包含前导 0 ,且它是整数 51 = 5 的二进制表示。
- 字符串 "1" 不包含前导 0 ,且它是整数 50 = 1 的二进制表示。
最少可以将 s 分成 2 个美丽子字符串。
示例 2:
输入:s = "111"
输出:3
解释:我们可以将输入字符串分成 ["1", "1", "1"] 。
- 字符串 "1" 不包含前导 0 ,且它是整数 50 = 1 的二进制表示。
最少可以将 s 分成 3 个美丽子字符串。
示例 3:
输入:s = "0"
输出:-1
解释:无法将给定字符串分成任何美丽子字符串。
提示:
1 <= s.length <= 15
s[i]
要么是 '0'
要么是 '1'
。
解法
方法一:记忆化搜索
题目中需要判断一个字符串是否是 $5$ 的幂的二进制表示,因此,我们不妨先预处理出所有 $5$ 的幂的数字,记录在哈希表 $ss$ 中。
接下来,我们设计一个函数 $dfs(i)$,表示从字符串 $s$ 的第 $i$ 个字符开始,到字符串末尾的最少分割次数。那么答案就是 $dfs(0)$。
函数 $dfs(i)$ 的计算方法如下:
- 如果 $i \geq n$,表示已经处理完了所有字符,那么答案就是 $0$;
- 如果 $s[i] = 0$,表示当前字符串包含前导 $0$,不符合美丽字符串的定义,因此答案是无穷大;
- 否则,我们从 $i$ 开始枚举子字符串的结束位置 $j$,用 $x$ 表示子字符串 $s[i..j]$ 的十进制值,如果 $x$ 在哈希表 $ss$ 中,那么我们就可以将 $s[i..j]$ 作为一个美丽子字符串,此时答案就是 $1 + dfs(j + 1)$。我们需要枚举所有可能的 $j$,并取所有答案中的最小值。
为了避免重复计算,我们可以使用记忆化搜索的方法。
在主函数中,我们首先预处理出所有 $5$ 的幂的数字,然后调用 $dfs(0)$,如果返回值为无穷大,那么说明无法将字符串 $s$ 分割成美丽子字符串,答案返回 $-1$,否则返回 $dfs(0)$ 的值。
时间复杂度 $O(n^2)$,空间复杂度 $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 | class Solution:
def minimumBeautifulSubstrings(self, s: str) -> int:
@cache
def dfs(i: int) -> int:
if i >= n:
return 0
if s[i] == "0":
return inf
x = 0
ans = inf
for j in range(i, n):
x = x << 1 | int(s[j])
if x in ss:
ans = min(ans, 1 + dfs(j + 1))
return ans
n = len(s)
x = 1
ss = {x}
for i in range(n):
x *= 5
ss.add(x)
ans = dfs(0)
return -1 if ans == inf else 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 | class Solution {
private Integer[] f;
private String s;
private Set<Long> ss = new HashSet<>();
private int n;
public int minimumBeautifulSubstrings(String s) {
n = s.length();
this.s = s;
f = new Integer[n];
long x = 1;
for (int i = 0; i <= n; ++i) {
ss.add(x);
x *= 5;
}
int ans = dfs(0);
return ans > n ? -1 : ans;
}
private int dfs(int i) {
if (i >= n) {
return 0;
}
if (s.charAt(i) == '0') {
return n + 1;
}
if (f[i] != null) {
return f[i];
}
long x = 0;
int ans = n + 1;
for (int j = i; j < n; ++j) {
x = x << 1 | (s.charAt(j) - '0');
if (ss.contains(x)) {
ans = Math.min(ans, 1 + dfs(j + 1));
}
}
return f[i] = 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 | class Solution {
public:
int minimumBeautifulSubstrings(string s) {
unordered_set<long long> ss;
int n = s.size();
long long x = 1;
for (int i = 0; i <= n; ++i) {
ss.insert(x);
x *= 5;
}
int f[n];
memset(f, -1, sizeof(f));
function<int(int)> dfs = [&](int i) {
if (i >= n) {
return 0;
}
if (s[i] == '0') {
return n + 1;
}
if (f[i] != -1) {
return f[i];
}
long long x = 0;
int ans = n + 1;
for (int j = i; j < n; ++j) {
x = x << 1 | (s[j] - '0');
if (ss.count(x)) {
ans = min(ans, 1 + dfs(j + 1));
}
}
return f[i] = ans;
};
int ans = dfs(0);
return ans > n ? -1 : 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 | func minimumBeautifulSubstrings(s string) int {
ss := map[int]bool{}
n := len(s)
x := 1
f := make([]int, n+1)
for i := 0; i <= n; i++ {
ss[x] = true
x *= 5
f[i] = -1
}
var dfs func(int) int
dfs = func(i int) int {
if i >= n {
return 0
}
if s[i] == '0' {
return n + 1
}
if f[i] != -1 {
return f[i]
}
f[i] = n + 1
x := 0
for j := i; j < n; j++ {
x = x<<1 | int(s[j]-'0')
if ss[x] {
f[i] = min(f[i], 1+dfs(j+1))
}
}
return f[i]
}
ans := dfs(0)
if ans > n {
return -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 | function minimumBeautifulSubstrings(s: string): number {
const ss: Set<number> = new Set();
const n = s.length;
const f: number[] = new Array(n).fill(-1);
for (let i = 0, x = 1; i <= n; ++i) {
ss.add(x);
x *= 5;
}
const dfs = (i: number): number => {
if (i === n) {
return 0;
}
if (s[i] === '0') {
return n + 1;
}
if (f[i] !== -1) {
return f[i];
}
f[i] = n + 1;
for (let j = i, x = 0; j < n; ++j) {
x = (x << 1) | (s[j] === '1' ? 1 : 0);
if (ss.has(x)) {
f[i] = Math.min(f[i], 1 + dfs(j + 1));
}
}
return f[i];
};
const ans = dfs(0);
return ans > n ? -1 : ans;
}
|