给定一个只包含 1 和 0 的字符串,返回 1 大于 0 的子字符串的数量

问题描述

假设 S 是一个只包含 0 和 1 的字符串,我想统计 S 的非空子串的个数,其中 0 的个数小于 1 的个数。

使用下面给出的蛮力方法,我们可以有一个算法在 O(n^2) 中解决这个问题:

moreOnes(s):
count = 0
n = s.len()

for i = 1 to n
    one = 0
    zero = 0
    for j = i to n
        if s[i] == '1'
            one++
        else
            zero++
        
        if one > zero
            count++

return count

但是我们能不能有一个算法的时间复杂度比 O(n*logn) 或 O(n) 更好,空间复杂度可以从 O(1) 到 O(n)?

解决方法

考虑一个数组 A[i],它包含范围 1..i 中的 1 数减去范围 1..i. 中的零数

有了这个数组,通过计算 A[j]-A[i-1],现在只需要 O(1) 时间来计算来自 i..j 的子字符串中 1 的数量减去 0 的数量。>

对于给定的端点 j,您希望找到所有起始点 iA[j]-A[i-1]>0。等效地,您想知道有多少 A[i-1] 的值小于 A[j]。

这可以通过 Fenwick trees 解决:

  1. 循环 j
  2. 在 Fenwick 树中的位置 A[j] 添加 1
  3. 从 Fenwick 树中查找累积值,范围高达 A[j]-1 - 这是以 j 结尾并满足所需的 1 多于 0 的属性的子串的数量。

Fenwick 树需要 O(n) 空间和 O(nlogn) 时间,因为每次查找都是 O(logn)。

(请注意,A[j] 可能会变为负数,而 Fenwick 树通常处理正数数据。您可以通过向 A[j] 添加常数偏移量 n 来解决此问题,以便所有条目都为正数。)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...