计数二进制子串

180 阅读1分钟

这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

问题描述

给定一个字符串 s,统计并返回具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是成组连续的。

重复出现(不同位置)的子串也要统计它们出现的次数。

示例 1:

输入:s = "00110011"
输出:6
解释:6 个子串满足具有相同数量的连续 10"0011""01""1100""10""0011""01" 。
注意,一些重复出现的子串(不同位置)要统计它们出现的次数。
另外,"00110011" 不是有效的子串,因为所有的 0(还有 1 )没有组合在一起。

示例 2:

输入:s = "10101"
输出:4
解释:有 4 个子串:"10""01""10""01" ,具有相同数量的连续 10

提示:

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

思路分析

首先我们先要理解一下题目意思,题目会给我们一个字符串s,我们需要找到s中具有相同数量 0 和 1 的非空(连续)子字符串的数量,这里需要注意一下题目对于子串的要求:子字符串中的所有 0 和所有 1 都是成组连续的。意思是子字符串应该可以划分为两个部分,这两部分分别为连续的0和连续的1,如:00001111,该字符串是满足条件的一个字符串,其前半部分为0000,后半部分为1111,在此条件的限制下,题目也就变得很简单了。我们不难发现,满足条件的字符串应该都要是对称的字符串,那么我们从中间切开,每一个0都可以找到与其匹配的1进行组合,所以我们只需要找到每一段最长的子串,然后根据其对称性求出最长子串可以划分成更多短子串的数目,我们可以分为以下几个步骤进行解题:

  • 1、计算每一段最长子串的01的数目
  • 2、根据对称性算出包含子串数量
  • 3、计算完成后判断上一子串中可以复用的部分
  • 4、重复步骤 1~3,直到遍历完整个字符串

完整 AC 代码如下:

AC 代码

/**
 * @param {string} s
 * @return {number}
 */
var countBinarySubstrings = function (s) {
  let res = 0,
    zore = 0,
    one = 0;
  for (let i = 0; i < s.length; i++) {
    if (one > 0 && zore > 0 && s[i] != s[i - 1]) {
      res += Math.min(one, zore);
      s[i] == "0" ? (zore = 0) : (one = 0);
    }
    s[i] == "1" ? one++ : zore++;
  }
  res += Math.min(one, zore);
  return res;
};

说在后面

本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。