String 给定一个二进制字符串;10110";。查找所有子字符串的计数,其设置位计数的数量>;=N

String 给定一个二进制字符串;10110";。查找所有子字符串的计数,其设置位计数的数量>;=N,string,algorithm,String,Algorithm,我们可以用蛮力解决这个问题,获取所有可能的子字符串并检查设置的位计数是否大于n 我被要求在o(n)中解决这个问题。我找不到任何答案可以在o(n)中实现这一点 是否有可能获得0(n)中二进制字符串的所有可能子字符串?答案已更改(注意到问题陈述中的=) 制作两个索引-左和右 我们要计算从位置左侧开始的子字符串,该位置至少包含k个 首先向右移动直到位计数达到k 现在我们有一些“好”的子字符串,从左开始,在右之后的任何位置结束,因此我们可以将len(s)-right+1添加到结果中 将左增加1,直到下一

我们可以用蛮力解决这个问题,获取所有可能的子字符串并检查设置的位计数是否大于n

我被要求在o(n)中解决这个问题。我找不到任何答案可以在o(n)中实现这一点

是否有可能获得0(n)中二进制字符串的所有可能子字符串?

答案已更改(注意到问题陈述中的
=

制作两个索引-

我们要计算从位置
左侧开始的子字符串,该位置至少包含
k

首先向右移动
直到位计数达到
k

现在我们有一些“好”的子字符串,从
左开始,在
右之后的任何位置结束,因此我们可以将
len(s)-right+1添加到结果中

增加1,直到下一个
下一个

重复向右移动
,依此类推。算法是线性的

Python示例:

s = '0010110010'
#s = '110010110010'
k = 2
left = 0
right = 0
res = 0
cnt = 0
while right < len(s):
    while (right < len(s)) and (cnt < k):
        if s[right] == "1":
            cnt += 1
        right +=1
    while (left <= right) and (cnt >= k):
        addend = len(s) + 1 - right
        res += addend
        print(left, right, addend, res)  #intermediate debug output
        if s[left] == "1":
            cnt -= 1
        left +=1
print(res)

0 5 6 6
1 5 6 12
2 5 6 18
3 6 5 23
4 6 5 28
5 9 2 30
30
s='0010110010'
#s='110010110010'
k=2
左=0
右=0
res=0
cnt=0
右侧
答案已更改(注意到问题陈述中的
=

制作两个索引-

我们要计算从位置
左侧开始的子字符串,该位置至少包含
k

首先向右移动
直到位计数达到
k

现在我们有一些“好”的子字符串,从
左开始,在
右之后的任何位置结束,因此我们可以将
len(s)-right+1添加到结果中

增加1,直到下一个
下一个

重复向右移动
,依此类推。算法是线性的

Python示例:

s = '0010110010'
#s = '110010110010'
k = 2
left = 0
right = 0
res = 0
cnt = 0
while right < len(s):
    while (right < len(s)) and (cnt < k):
        if s[right] == "1":
            cnt += 1
        right +=1
    while (left <= right) and (cnt >= k):
        addend = len(s) + 1 - right
        res += addend
        print(left, right, addend, res)  #intermediate debug output
        if s[left] == "1":
            cnt -= 1
        left +=1
print(res)

0 5 6 6
1 5 6 12
2 5 6 18
3 6 5 23
4 6 5 28
5 9 2 30
30
s='0010110010'
#s='110010110010'
k=2
左=0
右=0
res=0
cnt=0
右侧
设N=1的计数 设M=0的计数

int sum = 0 ;
for( int i = n ; i <= N; i++ ) sum += C(N,i) ;
sum *= 1<<M ;
int和=0;
对于(int i=n;i设n=1的计数)
设M=0的计数

int sum = 0 ;
for( int i = n ; i <= N; i++ ) sum += C(N,i) ;
sum *= 1<<M ;
int和=0;

对于(int i=n;i而言,一个有用的方法是问问自己,有多少子字符串的位集小于
n
位集

如果你能回答这个问题,那么原始问题的答案就在拐角处

为什么修改后的问题更容易理解?因为当你有一个子串时,比如说
S
,精确地设置了
n
位,那么任何包含
S
的子串将至少设置了
n
位,所以你不需要检查其中任何一个

假设你有一个子串。如果它设置了少于
n
位,你可以增加它以容纳更多位。如果它设置了
n
或更多位,它不能增加,你必须缩小它

假设从最左边的空子字符串开始,开始索引0,结束索引0,长度0。(当然,这是一个半开区间)。它没有设置位,因此您可以对其进行增长。它可以增长的唯一方向是向右,通过增加其末端索引。它不断增长,直到吃掉
n
1位;现在它必须收缩。它应该如何收缩?显然是在相反方向收缩(减少其末端索引)将一事无成。您将得到刚刚检查过的子字符串!因此,您应该通过增加其起始索引从左侧收缩它。因此,它不断收缩,直到从后端排出1位。现在它有
n-1
1位,并且可以再次增长


不难看出,您将以这种方式枚举小于
n
位的所有字符串。

一种有用的方法是问问自己,有多少子字符串的位小于
n

如果你能回答这个问题,那么原始问题的答案就在拐角处

为什么修改后的问题更容易理解?因为当你有一个子串时,比如说
S
,精确地设置了
n
位,那么任何包含
S
的子串将至少设置了
n
位,所以你不需要检查其中任何一个

假设你有一个子串。如果它设置了少于
n
位,你可以增加它以容纳更多位。如果它设置了
n
或更多位,它不能增加,你必须缩小它

假设从最左边的空子字符串开始,开始索引0,结束索引0,长度0。(当然,这是一个半开区间)。它没有设置位,因此您可以对其进行增长。它可以增长的唯一方向是向右,通过增加其末端索引。它不断增长,直到吃掉
n
1位;现在它必须收缩。它应该如何收缩?显然是在相反方向收缩(减少其末端索引)将一事无成。您将得到刚才检查过的子字符串!因此,您应该通过增加其起始索引从左侧收缩它。因此,它会不断收缩,直到从后端排出1位。现在它有
n-1
1位,并且可以增长ag