LeetCode 题解工作台

完美分割的方案数

给你一个字符串 s ,每个字符是数字 '1' 到 '9' ,再给你两个整数 k 和 minLength 。 如果对 s 的分割满足以下条件,那么我们认为它是一个 完美 分割: s 被分成 k 段互不相交的子字符串。 每个子字符串长度都 至少 为 minLength 。 每个子字符串的第一个字符都是一…

category

2

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

我们定义 表示前 个字符分割成 段的方案数。初始化 $f[0][0] = 1$,其余 $f[i][j] = 0$。 首先,我们需要判断第 个字符是否能成为第 段的最后一个字符,它需要同时满足以下条件:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个字符串 s ,每个字符是数字 '1' 到 '9' ,再给你两个整数 k 和 minLength 。

如果对 s 的分割满足以下条件,那么我们认为它是一个 完美 分割:

  • s 被分成 k 段互不相交的子字符串。
  • 每个子字符串长度都 至少 为 minLength 。
  • 每个子字符串的第一个字符都是一个 质数 数字,最后一个字符都是一个 非质数 数字。质数数字为 '2' ,'3' ,'5' 和 '7' ,剩下的都是非质数数字。

请你返回 s 的 完美 分割数目。由于答案可能很大,请返回答案对 109 + 7 取余 后的结果。

一个 子字符串 是字符串中一段连续字符串序列。

 

示例 1:

输入:s = "23542185131", k = 3, minLength = 2
输出:3
解释:存在 3 种完美分割方案:
"2354 | 218 | 5131"
"2354 | 21851 | 31"
"2354218 | 51 | 31"

示例 2:

输入:s = "23542185131", k = 3, minLength = 3
输出:1
解释:存在一种完美分割方案:"2354 | 218 | 5131" 。

示例 3:

输入:s = "3312958", k = 3, minLength = 1
输出:1
解释:存在一种完美分割方案:"331 | 29 | 58" 。

 

提示:

  • 1 <= k, minLength <= s.length <= 1000
  • s 每个字符都为数字 '1' 到 '9' 之一。
lightbulb

解题思路

方法一:动态规划

我们定义 f[i][j]f[i][j] 表示前 ii 个字符分割成 jj 段的方案数。初始化 f[0][0]=1f[0][0] = 1,其余 f[i][j]=0f[i][j] = 0

首先,我们需要判断第 ii 个字符是否能成为第 jj 段的最后一个字符,它需要同时满足以下条件:

  1. ii 个字符是一个非质数;
  2. i+1i+1 个字符是一个质数,或者第 ii 个字符是整个字符串的最后一个字符。

如果第 ii 个字符不能成为第 jj 段的最后一个字符,那么 f[i][j]=0f[i][j]=0。否则有:

f[i][j]=t=0iminLengthf[t][j1]f[i][j]=\sum_{t=0}^{i-minLength}f[t][j-1]

也就是说,我们要枚举上一段的结尾是哪个字符。这里我们用前缀和数组 g[i][j]=t=0if[t][j]g[i][j] = \sum_{t=0}^{i}f[t][j] 来优化枚举的时间复杂度。

那么有:

f[i][j]=g[iminLength][j1]f[i][j]=g[i-minLength][j-1]

时间复杂度 O(n×k)O(n \times k),空间复杂度 O(n×k)O(n \times k)。其中 nnkk 分别是字符串 ss 的长度和分割的段数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
    def beautifulPartitions(self, s: str, k: int, minLength: int) -> int:
        primes = '2357'
        if s[0] not in primes or s[-1] in primes:
            return 0
        mod = 10**9 + 7
        n = len(s)
        f = [[0] * (k + 1) for _ in range(n + 1)]
        g = [[0] * (k + 1) for _ in range(n + 1)]
        f[0][0] = g[0][0] = 1
        for i, c in enumerate(s, 1):
            if i >= minLength and c not in primes and (i == n or s[i] in primes):
                for j in range(1, k + 1):
                    f[i][j] = g[i - minLength][j - 1]
            for j in range(k + 1):
                g[i][j] = (g[i - 1][j] + f[i][j]) % mod
        return f[n][k]
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for the candidate's understanding of dynamic programming with state transitions.

  • question_mark

    Check if the candidate suggests a greedy approach in combination with dynamic programming.

  • question_mark

    Evaluate if the candidate considers edge cases such as large strings and the modulo operation.

warning

常见陷阱

外企场景
  • error

    Failing to handle partitions with leading zeros.

  • error

    Overcomplicating the problem by not applying the greedy approach effectively.

  • error

    Ignoring the modulo operation and producing numbers too large to handle.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Consider a variation where the number of partitions k is fixed, but the minimum length minLength varies.

  • arrow_right_alt

    Explore a scenario where the string contains only a single digit repeated, requiring careful handling of partitions.

  • arrow_right_alt

    Try solving the problem with a more restrictive set of partition conditions, such as ensuring each partition forms a valid number.

help

常见问题

外企场景

完美分割的方案数题解:状态·转移·动态规划 | LeetCode #2478 困难