1573. 分割字符串的方案数

目录

将二进制字符串分割成3部分,保证每部分1的个数相同 — 题解与分析

题目描述

题目背景与意义

解题分析

1. 问题关键:每个子串中 '1' 的数量相等

2. 特殊情况:count_1 == 0

3. 一般情况:count_1 可整除3

解题方法

代码分析与复杂度

示例说明

小结与比较

结语


将二进制字符串分割成3部分,保证每部分1的个数相同 — 题解与分析

题目描述

给定一个只包含 '0''1' 的二进制字符串 s,要求将其分割成三个 非空 字符串 s1, s2, s3(满足 s1 + s2 + s3 = s),使得这三个子串中 '1' 的数量都相等。

请返回满足条件的分割方案数。由于答案可能很大,需对 10^9 + 7 取模。


题目背景与意义

这个题目考察对字符串的计数、分割和组合的理解,特别是如何高效处理字符串中某种字符的分布以及分割点的选择。此类问题在字符串算法、动态规划、数学计数等领域都非常典型,尤其是在对“满足某种均分条件的多段划分方案”求解时常用技巧。


解题分析

1. 问题关键:每个子串中 '1' 的数量相等

  • 设字符串长度为 n
  • 统计字符串中 '1' 的总数为 count_1
  • 如果 count_1 不能被3整除,显然无法均分成三个部分,返回0。
  • 如果 count_1 是0,则字符串中全是0,此时只需统计分割点的组合数。
  • 如果 count_1 是3的倍数,设 target = count_1 / 3,每个子串中应包含 target'1'

2. 特殊情况:count_1 == 0

字符串全为0,三部分的 '1' 数都为0,满足条件。
分割方式就是在 n-1 个位置中选两个分割点。
组合数为:C(n-1, 2) = \frac{(n-1)(n-2)}{2}

3. 一般情况:count_1 可整除3

  • 找到字符串中所有 '1' 的位置索引,记为 ones_positions
  • 设目标每部分 '1' 数为 target
  • 则:
    • target'1' 的索引是 ones_positions[target - 1]
    • target + 1'1' 的索引是 ones_positions[target]
    • 2 * target'1' 的索引是 ones_positions[2 * target - 1]
    • 2 * target + 1'1' 的索引是 ones_positions[2 * target]
  • 第一个分割点可以放在第 target'1' 后的所有位置(在 ones_positions[target - 1]ones_positions[target] 之间的位置)
  • 第二个分割点可以放在第 2 * target'1' 后的所有位置(在 ones_positions[2 * target - 1]ones_positions[2 * target] 之间的位置)

方案数为:

(第一个分割点的可选位置数) × (第二个分割点的可选位置数) = (ones_positions[target] − ones_positions [ target − 1 ] ) × ( ones_positions [ 2 ∗ target ] − ones_positions [ 2 ∗ target − 1 ] )


解题方法

根据上面的分析,代码实现如下:

class Solution:
    def numWays(self, s: str) -> int:
        MOD = 10**9 + 7
        n = len(s)
        count_1 = s.count('1')

        # 全为0的情况
        if count_1 == 0:
            return ((n - 1) * (n - 2) // 2) % MOD
        
        # 不能被3整除的情况
        if count_1 % 3 != 0:
            return 0
        
        target = count_1 // 3
        ones_positions = [i for i, ch in enumerate(s) if ch == '1']
        
        first_cut_start = ones_positions[target - 1]
        first_cut_end = ones_positions[target]
        second_cut_start = ones_positions[2 * target - 1]
        second_cut_end = ones_positions[2 * target]
        
        ways = (first_cut_end - first_cut_start) * (second_cut_end - second_cut_start)
        return ways % MOD

代码分析与复杂度

  • 统计 '1' 数量时间复杂度为 O(n)。
  • 收集所有 '1' 的位置时间复杂度为 O(n)。
  • 计算方案数为 O(1)。
  • 总体时间复杂度:O(n),非常高效。
  • 空间复杂度:O(k),k 为字符串中 '1' 的个数。

示例说明

假设输入:

s = "10101"
  • 总的 '1' 个数 count_1 = 3,能被3整除,target = 1
  • '1' 的位置为 [0, 2, 4]
  • target=1'1' 位置:ones_positions[0] = 0
  • target+1=2'1' 位置:ones_positions[1] = 2
  • 2*target=2'1' 位置:ones_positions[1] = 2
  • 2*target+1=3'1' 位置:ones_positions[2] = 4

计算:

  • 第一个切分区间长度:2 - 0 = 2(即切分点可以在索引1或2)
  • 第二个切分区间长度:4 - 2 = 2(切分点可以在索引3或4)

方案数为 2 * 2 = 4

具体分割方案为:

  • s1 = s[0:1] = "1", s2 = s[1:3] = "01", s3 = s[3:] = "01"
  • s1 = s[0:1] = "1", s2 = s[1:4] = "010", s3 = s[4:] = "1"
  • s1 = s[0:2] = "10", s2 = s[2:3] = "1", s3 = s[3:] = "01"
  • s1 = s[0:2] = "10", s2 = s[2:4] = "10", s3 = s[4:] = "1"

均满足每部分 '1' 个数相同。


小结与比较

  • 简单暴力方法:枚举所有分割点,统计每段 '1' 的数量,时间复杂度高达 O(n²),不可行。
  • 前缀和方法:利用前缀和快速统计每段 '1' 数量,复杂度虽然降低,但仍然高。
  • 本题最优方案:通过统计 '1' 的位置,利用数学规律快速计算方案数,时间复杂度 O(n),空间复杂度 O(k)。

该方法既简洁又高效,是处理均分字符问题的典范。


结语

通过对字符串中 '1' 分布的观察与分析,结合数学组合的思想,我们能够快速计算满足均分条件的分割方案数。此题不仅锻炼了字符串处理能力,更体现了用数学思想简化问题的重要性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值