Leetcode 3234. Count the Number of Substrings With Dominant Ones

1. 解题思路

这一题要求被1 dominate的substring的个数,整体上来说是一个 O ( N 2 ) O(N^2) O(N2)算法复杂度的东西,还挺麻烦的,所幸题中限制了1的个数需要多于0的平方数,因此我们可以反其道而行,依次考察所有存在 i i i个零的substring,看看其中有多少个满足1的个数不少于 i 2 i^2 i2,将其累加即为我们最终的答案,如此一来,整体的算法复杂度可以优化至 O ( N 3 / 2 ) O(N^{3/2}) O(N3/2),勉强可以接受吧。

于是,我们只需要给出所有0所在的位置,然后考察所有恰好存在 i i i个0的区间,然后看看有多少个满足至少存在 i 2 i^2 i2个1。假设对应的窗口之间有 m m m个1,然后区间左右分别有 l , r l,r l,r个1,此时,我们不难通过容斥原理得到对应的数学解答如下:

N = ( ∑ i = 1 l + r − ( i 2 − m ) + 1 i ) − ( ∑ i = 1 l − ( i 2 − m ) + 1 i ) + m a x ( 0 , l − ( i 2 − m ) + 1 ) − ( ∑ i = 1 r − ( i 2 − m ) + 1 i ) + m a x ( 0 , r − ( i 2 − m ) + 1 ) N = (\sum\limits_{i=1}^{l+r-(i^2-m)+1} i) - (\sum\limits_{i=1}^{l-(i^2-m)+1} i) + \mathop{max}(0, l-(i^2-m)+1) - (\sum\limits_{i=1}^{r-(i^2-m)+1} i) + \mathop{max}(0, r-(i^2-m)+1) N=(i=1l+r(i2m)+1i)(i=1l(i2m)+1i)+max(0,l(i2m)+1)(i=1r(i2m)+1i)+max(0,r(i2m)+1)

而等差数列的求解又可以直接写作 ∑ i = 1 n = n ( n + 1 ) 2 \sum\limits_{i=1}^n = \frac{n(n+1)}{2} i=1n=2n(n+1),因此,我们不难在 O ( 1 ) O(1) O(1)的时间复杂度范围内直接获得对应的答案。

综上,总的时间复杂度就是 O ( N 3 / 2 ) O(N^{3/2}) O(N3/2),不算很好,但是勉强够用吧……

2. 代码实现

给出python代码实现如下:

class Solution:
    def numberOfSubstrings(self, s: str) -> int:
        n = len(s)
        zeros = [i for i, ch in enumerate(s) if ch == "0"]
        if len(zeros) <= 1:
            return n * (n+1) // 2 - len(zeros)
        
        m = len(zeros)
        ans = (n-1 - zeros[-1]) * (n - zeros[-1]) // 2
        for i in range(m):
            if i == 0:
                one = zeros[i]
            else:
                one = zeros[i] - zeros[i-1]-1
            ans += one*(one+1) // 2
        for i in range(1, m+1):
            if i*i+i > n:
                break
            for j in range(m+1-i):
                l, r = zeros[j], zeros[i+j-1]
                mid = r-l+1-i
                l1 = l if j == 0 else zeros[j] - zeros[j-1]-1
                r1 = n-1-r if i+j-1 == m-1 else zeros[i+j] - zeros[i+j-1]-1
                if mid >= i*i:
                    need = 0
                    cnt = (l1+1) * (r1+1)
                elif mid + l1 + r1 >= i*i:
                    need = i*i-mid
                    cnt = (l1+r1-need+1) * (l1+r1-need+2) // 2
                    if l1 >= need:
                        cnt = cnt - ((l1-need+1) * (l1-need+2) // 2) + (l1-need+1)
                    if r1 >= need:
                        cnt = cnt - ((r1-need+1) * (r1-need+2) // 2) + (r1-need+1)
                else:
                    need = 0
                    cnt = 0
                ans += cnt
        return ans      

提交代码评测得到:耗时7478ms,占用内存18.4MB。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值