这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
问题描述
给定一个字符串 s,统计并返回具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是成组连续的。
重复出现(不同位置)的子串也要统计它们出现的次数。
示例 1:
输入:s = "00110011"
输出:6
解释:6 个子串满足具有相同数量的连续 1 和 0 :"0011"、"01"、"1100"、"10"、"0011" 和 "01" 。
注意,一些重复出现的子串(不同位置)要统计它们出现的次数。
另外,"00110011" 不是有效的子串,因为所有的 0(还有 1 )没有组合在一起。
示例 2:
输入:s = "10101"
输出:4
解释:有 4 个子串:"10"、"01"、"10"、"01" ,具有相同数量的连续 1 和 0 。
提示:
- 1 <= s.length <= 10^5
- s[i] 为 '0' 或 '1'
思路分析
首先我们先要理解一下题目意思,题目会给我们一个字符串s,我们需要找到s中具有相同数量 0 和 1 的非空(连续)子字符串的数量,这里需要注意一下题目对于子串的要求:子字符串中的所有 0 和所有 1 都是成组连续的。意思是子字符串应该可以划分为两个部分,这两部分分别为连续的0和连续的1,如:00001111,该字符串是满足条件的一个字符串,其前半部分为0000,后半部分为1111,在此条件的限制下,题目也就变得很简单了。我们不难发现,满足条件的字符串应该都要是对称的字符串,那么我们从中间切开,每一个0都可以找到与其匹配的1进行组合,所以我们只需要找到每一段最长的子串,然后根据其对称性求出最长子串可以划分成更多短子串的数目,我们可以分为以下几个步骤进行解题:
- 1、计算每一段最长子串的
0和1的数目 - 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;
};
说在后面
本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。