返回介绍

solution / 1500-1599 / 1573.Number of Ways to Split a String / README

发布于 2024-06-17 01:03:17 字数 4790 浏览 0 评论 0 收藏 0

1573. 分割字符串的方案数

English Version

题目描述

给你一个二进制串 s  (一个只包含 0 和 1 的字符串),我们可以将 s 分割成 3 个 非空 字符串 s1, s2, s3 (s1 + s2 + s3 = s)。

请你返回分割 s 的方案数,满足 s1,s2 和 s3 中字符 '1' 的数目相同。

由于答案可能很大,请将它对 10^9 + 7 取余后返回。

 

示例 1:

输入:s = "10101"
输出:4
解释:总共有 4 种方法将 s 分割成含有 '1' 数目相同的三个子字符串。
"1|010|1"
"1|01|01"
"10|10|1"
"10|1|01"

示例 2:

输入:s = "1001"
输出:0

示例 3:

输入:s = "0000"
输出:3
解释:总共有 3 种分割 s 的方法。
"0|0|00"
"0|00|0"
"00|0|0"

示例 4:

输入:s = "100100010100110"
输出:12

 

提示:

  • s[i] == '0' 或者 s[i] == '1'
  • 3 <= s.length <= 10^5

解法

方法一:计数

我们先遍历字符串 $s$,统计其中字符 $1$ 的个数 $cnt$,如果 $cnt$ 不能被 $3$ 整除,那么无法分割,直接返回 $0$。如果 $cnt$ 为 $0$,说明字符串中没有字符 $1$,我们可以在 $n-1$ 个位置中任意选择两个位置,将字符串分割成三个子串,那么方案数就是 $C_{n-1}^2$。

如果 $cnt \gt 0$,我们将 $cnt$ 更新为 $\frac{cnt}{3}$,即每个子串中字符 $1$ 的个数。

接下来我们找到第一个子字符串的右边界的最小下标,记为 $i_1$,第一个子字符串的右边界的最大下标(不包含),记为 $i_2$;第二个子字符串的右边界的最小下标,记为 $j_1$,第二个子字符串的右边界的最大下标(不包含),记为 $j_2$。那么方案数就是 $(i_2-i_1) \times (j_2-j_1)$。

注意答案可能很大,需要对 $10^9+7$ 取模。

时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为字符串 $s$ 的长度。

相似题目:

class Solution:
  def numWays(self, s: str) -> int:
    def find(x):
      t = 0
      for i, c in enumerate(s):
        t += int(c == '1')
        if t == x:
          return i

    cnt, m = divmod(sum(c == '1' for c in s), 3)
    if m:
      return 0
    n = len(s)
    mod = 10**9 + 7
    if cnt == 0:
      return ((n - 1) * (n - 2) // 2) % mod
    i1, i2 = find(cnt), find(cnt + 1)
    j1, j2 = find(cnt * 2), find(cnt * 2 + 1)
    return (i2 - i1) * (j2 - j1) % (10**9 + 7)
class Solution {
  private String s;

  public int numWays(String s) {
    this.s = s;
    int cnt = 0;
    int n = s.length();
    for (int i = 0; i < n; ++i) {
      if (s.charAt(i) == '1') {
        ++cnt;
      }
    }
    int m = cnt % 3;
    if (m != 0) {
      return 0;
    }
    final int mod = (int) 1e9 + 7;
    if (cnt == 0) {
      return (int) (((n - 1L) * (n - 2) / 2) % mod);
    }
    cnt /= 3;
    long i1 = find(cnt), i2 = find(cnt + 1);
    long j1 = find(cnt * 2), j2 = find(cnt * 2 + 1);
    return (int) ((i2 - i1) * (j2 - j1) % mod);
  }

  private int find(int x) {
    int t = 0;
    for (int i = 0;; ++i) {
      t += s.charAt(i) == '1' ? 1 : 0;
      if (t == x) {
        return i;
      }
    }
  }
}
class Solution {
public:
  int numWays(string s) {
    int cnt = 0;
    for (char& c : s) {
      cnt += c == '1';
    }
    int m = cnt % 3;
    if (m) {
      return 0;
    }
    const int mod = 1e9 + 7;
    int n = s.size();
    if (cnt == 0) {
      return (n - 1LL) * (n - 2) / 2 % mod;
    }
    cnt /= 3;
    auto find = [&](int x) {
      int t = 0;
      for (int i = 0;; ++i) {
        t += s[i] == '1';
        if (t == x) {
          return i;
        }
      }
    };
    int i1 = find(cnt), i2 = find(cnt + 1);
    int j1 = find(cnt * 2), j2 = find(cnt * 2 + 1);
    return (1LL * (i2 - i1) * (j2 - j1)) % mod;
  }
};
func numWays(s string) int {
  cnt := 0
  for _, c := range s {
    if c == '1' {
      cnt++
    }
  }
  m := cnt % 3
  if m != 0 {
    return 0
  }
  const mod = 1e9 + 7
  n := len(s)
  if cnt == 0 {
    return (n - 1) * (n - 2) / 2 % mod
  }
  cnt /= 3
  find := func(x int) int {
    t := 0
    for i := 0; ; i++ {
      if s[i] == '1' {
        t++
        if t == x {
          return i
        }
      }
    }
  }
  i1, i2 := find(cnt), find(cnt+1)
  j1, j2 := find(cnt*2), find(cnt*2+1)
  return (i2 - i1) * (j2 - j1) % mod
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文