LeetCode.696 计数二进制子串

41 阅读2分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

题目描述:

696. 计数二进制子串 - 力扣(LeetCode)

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

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

示例一

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

示例二

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

提示:

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

思路分析

观察一下:

  1. 首先子串长度是偶数
  2. 当长度为2时,可能的有“01”,“10”
  3. 当长度为4时,可能的有“0011”,“1100”
  4. 当长度为6时,可能的有“000111”,“111000”
  5. 发现:长度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 中心扩展(与回文串相似)/分组的方法 - 计数二…

参考

696. 计数二进制子串 题解 - 力扣(LeetCode)

超过100% Java 动态规划 贪心算法 简单易懂 - 计数二进制子串 - 力扣(LeetCode)