给出一个二进制字符串。如何在字符串的特定范围内找到“ 010” 的出现。
例如,我有字符串“ 0100110” 。如果给定范围为 3 7 (基于1的索引),则输出将为 4 。我找不到解决它的更快方法。
尝试此操作时,我可以以 O(N)的复杂性来解决它。方法是-首先,我指出所有'1'在一定范围内的位置,然后使用这些位置,我找出后面两个'0'来回然后,将在后面找到的'0'的数量与单个'1'的数量乘以在后面找到的'0'的数量。然后将一定范围内每个'1'的相乘结果相加。
对于给定的示例,'1'在范围内的位置为 {5,6} 。现在,对于索引 5 ,我前后的数字分别为 2 和 1 。这样我们就可以将子序列“ 010” 设置为 2 。同样,对于索引 6 ,我们也得到的答案是 2 。我们总共可以将子序列“ 010” 总共进行 4 次。
但是当我们对给定的字符串有一定范围内的多个 Q 查询时,我的方法很容易达到时间复杂度 O(N 2 ) 。我尝试了很多,但是没有找到优化方法。有人可以用小于 O(N 2 )个复杂度的方法来帮助我吗?提及的时限应为 1秒。如果您提供伪代码,将是一个加号。
〜先谢谢了。
答案 0 :(得分:4)
预处理:制作辅助数组,该数组包含到给定位置的累积零个数(aux [0] = 0)
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
对于给定的L..R
范围扫描为1,对于1
的每k个索引,获取范围内的零个数-O(1)操作
P[k] = (A[k] - A[L-1]) * (A[R] - A[k])
S = Sum(P[k], k=L..R)
因此,每个查询有O(R-L)
个时间,Q个查询有最差情况O(Q*N)
但是要仔细看公式:
P[k] = (A[k] - A[L-1]) * (A[R] - A[k]) =
A[k] * (A[R] + A[L-1]) - A[k]^2 - A[R] * A[L-1] =
A[k] * LRSum - A[k]^2 - LRProd
S = Sum(A[k] for ones) * LRSum - Sum(A[k]^2) - LRProd * NumOfOnes
请注意,LRSum
和LRProd
是给定查询的常量,我们必须计算1位置的A [k]之和和相同位置的平方和。似乎我们可以使用相同的累积数组概念,并在每个查询中以O(1)
的形式获取结果。
快速检查给出(3+3)*5 - (9+9) - 4*2 = 30-18-8 = 4
作为您的示例。
使用累积数组:
0 1 0 0 1 1 0 //string
0 1 1 2 3 3 3 4 //aux array A[]
0 0 1 1 1 4 7 7 //aux array B[]
0 0 1 1 1 10 19 19 //aux array C[]
Result = (B[R] - B[L-1]) * (A[R] + A[L-1]) - (C[R] - C[L-1]) -
A[R] * A[L-1] * (R - L - 1 - (A[R] - A[L-1])) =
(7-1) * (4 + 1) - (19 - 1) - 4 * 1 * (7 - 2 - 4 + 1) = 4