列表

详情


6923. 将字符串分割为最少的美丽子字符串

给你一个二进制字符串 s ,你需要将字符串分割成一个或者多个 子字符串  ,使每个子字符串都是 美丽 的。

如果一个字符串满足以下条件,我们称它是 美丽 的:

请你返回分割后的子字符串的 最少 数目。如果无法将字符串 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
解释:无法将给定字符串分成任何美丽子字符串。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int minimumBeautifulSubstrings(string s) { } };

java 解法, 执行用时: 2 ms, 内存消耗: 41 MB, 提交时间: 2023-07-10 09:41:06

class Solution {
    public final static String[] fiveN;
    static{
        fiveN = new String[7];
        fiveN[0] = "1";
        fiveN[1] = "101";
        fiveN[2] = "11001";
        fiveN[3] = "1111101";
        fiveN[4] = "1001110001";
        fiveN[5] = "110000110101";
        fiveN[6] = "11110100001001";
    }
    /**
     *  参考0x3f大佬的题解
     *  dp[i]表示从i开始最少分成多少段
     *  状态转移 : dp[i] = dp[i + m] + 1; ( m 为 5 的幂的二进制的长度)
     */
    public int minimumBeautifulSubstrings(String s) {
        int n = s.length();
        int[] dp = new int[n + 1];
        dp[n] = 0;
        for(int i = n - 1; i >= 0; i--) {
            dp[i] = 16;
            if(s.charAt(i) == '0') continue;
            for(String fivesn : fiveN) {
                if(i + fivesn.length() > n) break;
                if(s.substring(i, i + fivesn.length()).equals(fivesn)) {
                    dp[i] = Math.min(dp[i], dp[i + fivesn.length()] + 1);
                }
            }
        }
        return dp[0] > n ? -1 : dp[0];
    }
}

golang 解法, 执行用时: 0 ms, 内存消耗: 2 MB, 提交时间: 2023-07-10 09:39:38

var pow5 []string

func init() {
	// 预处理 2**15 以内的 5 的幂
	for p5 := 1; p5 < 1<<15; p5 *= 5 {
		pow5 = append(pow5, strconv.FormatUint(uint64(p5), 2))
	}
}

func minimumBeautifulSubstrings(s string) int {
	n := len(s)
	f := make([]int, n+1)
	for i := n - 1; i >= 0; i-- {
		f[i] = n + 1
		if s[i] == '0' {
			continue
		}
		for _, t := range pow5 {
			if i+len(t) > n {
				break
			}
			if s[i:i+len(t)] == t {
				f[i] = min(f[i], f[i+len(t)]+1)
			}
		}
	}
	if f[0] > n {
		return -1
	}
	return f[0]
}

func min(a, b int) int { if b < a { return b }; return a }

python3 解法, 执行用时: 56 ms, 内存消耗: 16 MB, 提交时间: 2023-07-10 09:38:54

'''
递推
'''
# 预处理 2**15 以内的 5 的幂
pow5 = [bin(5 ** i)[2:] for i in range(7)]

class Solution:
    def minimumBeautifulSubstrings(self, s: str) -> int:
        n = len(s)
        f = [inf] * n + [0]
        for i in range(n - 1, -1, -1):
            if s[i] == '0': continue
            for t in pow5:
                if i + len(t) > n:
                    break
                if s[i: i + len(t)] == t:  # 忽略切片的时间,这里的比较视作均摊 O(1)
                    f[i] = min(f[i], f[i + len(t)] + 1)
        return f[0] if f[0] < inf else -1

python3 解法, 执行用时: 52 ms, 内存消耗: 16.2 MB, 提交时间: 2023-07-10 09:37:19

'''
记忆化搜索
dfs(i): 划分从s[i]开始的后缀,最少要划分多少段。

'''
# 预处理 2**15 以内的 5 的幂
pow5 = [bin(5 ** i)[2:] for i in range(7)]

class Solution:
    def minimumBeautifulSubstrings(self, s: str) -> int:
        n = len(s)
        @cache
        def dfs(i: int) -> int:
            if i == n: return 0
            if s[i] == '0': return inf  # 不能包含前导 0
            res = inf
            for t in pow5:
                if i + len(t) > n:
                    break
                if s[i: i + len(t)] == t:  # 忽略切片的时间,这里的比较视作均摊 O(1)
                    res = min(res, dfs(i + len(t)) + 1)
            return res
        ans = dfs(0)
        return ans if ans < inf else -1

上一题