1573. 分割字符串的方案数
大约 3 分钟
---
1573. 分割字符串的方案数
- 标签:数学、字符串
- 难度:中等
题目链接
题目大意
描述:给定一个二进制字符串 (只包含 和 )。可以将字符串分割成三个非空子字符串。
要求:返回分割方式的数目,使得三个子字符串中 的个数相同。结果对 取模。
说明:
- 。
示例:
- 示例 1:
输入:s = "10101"
输出:4
解释:总共有 4 种方法将 s 分割成含有 '1' 数目相同的三个子字符串。
"1|010|1"
"1|01|01"
"10|10|1"
"10|1|01"- 示例 2:
输入:s = "1001"
输出:0解题思路
思路 1:组合数学
1. 核心思想
设 为字符串中 的总数。
- 如果 ,不可能均分,返回 。
- 如果 ,在 个空隙中选择两个位置分割,方案数为 。
否则,每段应有 个 。
找到以下位置:
- 第一个 的累计数达到 的位置 (第一个分割点的可行范围)
- 累计数达到 的位置
- 累计数达到 的位置
- 累计数达到 的位置
第一个分割点的可行位置数 = 。
第二个分割点的可行位置数 = 。
方案数 = 两者相乘。
2. 具体步骤
第 1 步:统计 的总数 。如果 ,返回 。
如果 ,返回 。
第 2 步:。
第 3 步:遍历整个字符串,记录每个 的位置索引 数组。
第 4 步:
- 第一个分割点可以在 到 之间(即第 个 和第 个 之间)。
- 第二个分割点可以在 到 之间。
方案数 = 。
3. 举例说明
以 为例:
的个数 ,。
的位置:。
- 第一个分割点位置范围: → 可以是位置 (只在 和 之间,即下标 到 )。
实际上,第一个分割将 个给第一部分,第一部分需要有 个 。 的位置是 ,所以第一部分的结束位置 且 下一个 的位置 。
所以第一个分割点 (在第一个 后面、第二个 前面)。 - 第二个分割点位置范围: → 可以是位置 。
方案数 = 。
但实际上 长度 ,可能的三个非空子串的分割方式:
分割点位置 ():
:, , → 1 的个数 。
- 不对,第一部分从 到 ,即 。第二部分从 到 ,即 。第三部分从 到 ,即 。1 的个数:,不等。
:, , → 。✓
:, , → 。✓
:, , → 。✓
:, , → 。✓
实际上有 种。
方案数 。✓
思路 1:代码
class Solution:
def numWays(self, s: str) -> int:
MOD = 10 ** 9 + 7
n = len(s)
ones = [i for i, ch in enumerate(s) if ch == '1']
total = len(ones)
if total % 3 != 0:
return 0
if total == 0:
return (n - 1) * (n - 2) // 2 % MOD
target = total // 3
# 第一个分割点的可选项数
left_gap = ones[target] - ones[target - 1]
# 第二个分割点的可选项数
right_gap = ones[2 * target] - ones[2 * target - 1]
return left_gap * right_gap % MOD思路 1:复杂度分析
- 时间复杂度:。
- 空间复杂度:,存储 的位置。