本文正在参加「金石计划 . 瓜分6万现金大奖」
题目描述:
给定一个字符串 s
,统计并返回具有相同数量 0
和 1
的非空(连续)子字符串的数量,并且这些子字符串中的所有 0
和所有 1
都是成组连续的。
重复出现(不同位置)的子串也要统计它们出现的次数。
示例一
输入:s = "00110011"
输出:6
解释:6 个子串满足具有相同数量的连续 1 和 0 :"0011"、"01"、"1100"、"10"、"0011" 和 "01" 。
注意,一些重复出现的子串(不同位置)要统计它们出现的次数。
另外,"00110011" 不是有效的子串,因为所有的 0(还有 1 )没有组合在一起。
示例二
输入: s = "10101"
输出: 4
解释: 有 4 个子串:"10"、"01"、"10"、"01" ,具有相同数量的连续 1 和 0 。
提示:
1 <= s.length <= 10^5
s[i]
为'0'
或'1'
思路分析
观察一下:
- 首先子串长度是偶数
- 当长度为2时,可能的有“01”,“10”
- 当长度为4时,可能的有“0011”,“1100”
- 当长度为6时,可能的有“000111”,“111000”
- 发现:长度6包含了长度4,长度4包含了长度2
AC代码
class Solution {
fun countBinarySubstrings(s: String): Int {
var infos = ArrayList<Int>()
var zeroCount =0
var oneCount = 0
s.forEach{
if(it == '1'){
if(zeroCount > 0){
infos.add(zeroCount)
zeroCount = 0
}
oneCount++
}else{
if(oneCount >0){
infos.add(oneCount)
oneCount = 0
}
zeroCount++
}
}
if(zeroCount > 0){
infos.add(zeroCount)
zeroCount = 0
}
if(oneCount >0){
infos.add(oneCount)
oneCount = 0
}
var ans = 0
for(i in 0 until infos.size -1){
ans += Math.min(infos[i],infos[i+1])
}
return ans
}
}
总结
之前做过回文串的题目,这个其实也可以这么解。
如果将0与1看成对应,那么符合题目要求的子串就关于其中心(中间两个元素的中间)成轴对称。就如同回文字符串关于中心轴对称。不过有一点不同,就是在本问题中对称中心只能是两个字符的中间,而回文字符串的中心可以是某一个字母。
具体可以看这位大佬的解法:
696.java 中心扩展(与回文串相似)/分组的方法 - 计数二…