📅  最后修改于: 2023-12-03 14:50:06.506000             🧑  作者: Mango
在二进制串中,若连续的 $K$ 个比特位均为 $1$ 或 $0$,则称该二进制串具有 $K$ 个相邻设置位。
我们希望求出长度为 $N$ 的二进制串中具有 $K$ 个相邻设置位的数量。
如果我们知道了具有 $K-1$ 个相邻设置位的长度为 $N$ 的二进制串的数量,那么我们就可以通过在这些字符串的相邻设置位中插入一些 $1$ 来得到具有 $K$ 个相邻设置位的字符串。
考虑使用动态规划来解决该问题。
令 $dp_{i,j}$ 表示长度为 $i$,且以 $j$ 结尾的二进制串中具有 $K$ 个相邻设置位的数量。则最终答案即为 $\sum\limits_{j=0}^{1} dp_{N,j}$。
接下来考虑如何转移。对于一个 $dp_{i,j}$,我们可以在其后面插入 $0$ 或 $1$ 来得到下一位的二进制串。
若插入 $0$,则原来的 $j$ 可以变成 $0$ 或 $1$,得到的新状态为 $dp_{i+1,0}$ 或 $dp_{i+1,1}$。
若插入 $1$,则只有当原来的 $j$ 为 $0$ 时,才能得到一个相邻设置位,得到的新状态为 $dp_{i+1,1}$。
因此,我们可以得到状态转移方程为:
$$ dp_{i+1,0} = dp_{i,0} + dp_{i,1} $$
$$ dp_{i+1,1} = dp_{i,0} $$
转移时需要注意,由于我们只需要知道上一行的状态,因此可以使用滚动数组,将空间复杂度优化为 $O(1)$。
def count_binary_strings(n: int, k: int) -> int:
dp = [[0 for _ in range(2)] for _ in range(n)]
dp[0][0] = 1
dp[0][1] = 1
for i in range(1, n):
dp[i][0] = dp[i-1][0] + dp[i-1][1]
dp[i][1] = dp[i-1][0]
return dp[n-1][0] + dp[n-1][1] if k == 1 else dp[n-1][0]
n = 5
k = 2
print(count_binary_strings(n, k)) # 6
该算法的时间复杂度为 $O(N)$,空间复杂度为 $O(1)$。