【发布时间】:2020-08-11 12:16:00
【问题描述】:
我们可以蛮力解决这个问题,获取所有可能的子字符串并检查设置的位数是否大于 n。
我被要求在 o(n) 中解决这个问题。我找不到任何可以在 o(n) 中实现此目的的答案。
是否可以得到0(n)中所有可能的二进制字符串子串?
【问题讨论】:
我们可以蛮力解决这个问题,获取所有可能的子字符串并检查设置的位数是否大于 n。
我被要求在 o(n) 中解决这个问题。我找不到任何可以在 o(n) 中实现此目的的答案。
是否可以得到0(n)中所有可能的二进制字符串子串?
【问题讨论】:
答案已更改(在问题陈述中注意到 >=)。
创建两个索引 - left 和 right。
我们要考虑从位置left 开始的至少包含k ones 的子字符串。
首先移动right,直到位数达到k。
现在我们有一些“好”的子字符串从left 开始并在right 之后的任何位置结束,所以我们可以将len(s) - right + 1 添加到结果中。
将 left 递增 1,直到下一个 one。
重复移动right 等等。算法是线性的。
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
【讨论】:
让 N = '1' 的计数 并让 M = count of '0'
int sum = 0 ;
for( int i = n ; i <= N; i++ ) sum += C(N,i) ;
sum *= 1<<M ;
总和就是你的答案。
【讨论】:
substrings(连续片段)?
一个有用的方法是问自己有多少子字符串少于比n 位设置。
如果你能回答这个问题,那么原问题的答案就在眼前。
为什么修改后的问题更容易掌握?因为当您有一个子字符串时,比如说S,恰好设置了n 位,那么包含S 的任何 子字符串将至少设置n 位,所以您不需要需要检查其中任何一个。
假设你有一个子字符串。如果它设置的位少于n,您可以扩大它以容纳更多位。如果它设置了n 或更多位,则它无法增长,您必须缩小它。
假设从最左边的空子串开始,开始索引0,结束索引0,长度0。(当然是半开区间)。它没有设置位,因此您可以扩展它。它可以增长的唯一方向是向右,通过增加其结束索引。它不断增长,不断增长,直到它吃掉n 1-bits;现在它必须缩小。应该怎么缩?显然,在相反的方向收缩它(减少它的结束索引)将一事无成。您将得到一个刚刚检查过的子字符串!所以你应该通过增加它的起始索引来从左边缩小它。所以它会不断地收缩,不断地收缩,直到它从后端排出一个 1 位。现在它有n-1 1-bits,它可以再次增长。
不难证明你会枚举所有小于n位的字符串。
【讨论】: