[leetcode每日一题2020/8/10]696. 计数二进制子串

计数二进制子串

题目来源于leetcode,解法和思路仅代表个人观点。传送门
难度:简单
用时:00:20:00 (一开始没往最优算法想。。硬是想着优化了)

题目

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

重复出现的子串要计算它们出现的次数。

示例 1 :

输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。

请注意,一些重复出现的子串要计算它们出现的次数。

另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。

示例 2 :

输入: "10101"
输出: 4
解释: 有4个子串:“10”,“01”,“10”,“01”,它们具有相同数量的连续1和0。

注意:
s.length 在1到50,000之间。
s 只包含“0”或“1”字符。

思路

观察了一下示例,发现一个特点。
他们都是从左到右,枚举每个字符的情况。那么容易想出以下算法。

对于每个字符。

  1. 记录当前字符bit。
  2. 从当前字符开始,从左到右,先记录与bit相同字符的数量cnt1。再记录与bit不同字符的数量cnt2。
  3. 再次遇到与bit相同的字符时结束(或者到字符串末尾)。比较cnt1、cnt2。看是否相同,如果相同,总记录数ans++。
  4. 重复以上循环,直至遍历完整个字符串。

那么,简单计算一下,可以知道,算法时间复杂度是O(n2)。提交后果然超时了。那么接着想办法优化一下。


考虑下面两种情况:
一、 如果当前字符接下来找到相同数量不同字符

在这里插入图片描述
例如:这里从s[0]开始,到s[4]发现又找到了相同字符。

  1. 本来可以知道(在未优化的算法中),从s[0]可以找到"0011"。接着需要从s[1]开始遍历。
  2. 仔细分析,其实这时也可以知道s[1]可以找到"01"。
  3. 那么,在s[0]的这次遍历当中,就可以知道总记录ans应该加上本次找到"0"的数量cnt1,即ans+=cnt1。
  4. 同时,只需要把指针回溯到"1"开始的地方(这里是s[2]),即 i = j − c n t 2 − 1 i = j-cnt2-1 i=jcnt21(考虑到下个循环i会自己+1,所以这里多-1)

二、 如果当前字符接下来不能找到相同数量不同字符
在这里插入图片描述
例如:这里从s[0]开始,到s[3]发现又找到了相同字符。

  1. 本来可以知道(在未优化的算法中),从s[0]没找到可以匹配的串。接着需要从s[1]开始遍历。
  2. 仔细分析,其实这时也可以知道s[1]可以找到"01"。
  3. 在s[0]的这次遍历中,其实可以加上cnt1和cnt2当中的较小的那个。即ans+=cnt1>cnt2?cnt2:cnt1。
  4. 同时,只需要把指针回溯到"1"开始的地方(这里是s[2]),即 i = j − c n t 2 − 1 i = j-cnt2-1 i=jcnt21(考虑到下个循环i会自己+1,所以这里多-1)

这样,对于字符串较长的样例有更快的速度。

代码

class Solution {
    public int countBinarySubstrings(String s) {
        char bit;
        int ans = 0;
        int cnt1=0,cnt2=0;
        boolean flag = false;
        for(int i=0;i<s.length();i++){
            bit = s.charAt(i);
            cnt1=0;
            cnt2=0;
            flag = false;
            for(int j=i;j<s.length();j++){
                char temp1 = s.charAt(j);
                if(bit == temp1){
                    if(flag){
                        //加上比较小的数
                        ans += cnt1>cnt2?cnt2:cnt1;
                        i = j - cnt2 -1;
                        break;
                    }
                    cnt1++;
                }else{
                    flag = true;
                    cnt2++;
                }
                if(cnt1 == cnt2){
                    ans += cnt1;
                    i = j-cnt2;
                    break;
                }
            }

        }
        return ans;
    }
}

算法复杂度

时间复杂度: 粗略算了一下O(2*n)~O(n2) 。(不是很会算啊)
空间复杂度: O(1)。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值