📌  相关文章
📜  具有 K 个相邻设置位的长度为 N 的二进制串的数量(1)

📅  最后修改于: 2023-12-03 14:50:06.506000             🧑  作者: Mango

具有 $K$ 个相邻设置位的长度为 $N$ 的二进制串的数量

在二进制串中,若连续的 $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)$。