📅  最后修改于: 2023-12-03 14:58:33.805000             🧑  作者: Mango
本题是由 Sudo GATE 2020 Mock II(2019 年 1 月 10 日)|第 36 题 修改而来。本文将对该题进行详细解析。
门是一个由 0 和 1 组成的串。我们称门“好”如果它只由 0 和 1 组成且不存在 011 的子串(即,它的子串中不会有 011 这个形式的子串)。给定一个门的字符串 s,计算 s 中有多少个长为 k 的“好”子串。
例如,如果 s = "1010011010" 和 k = 3,则 s 中“好”的子串是 “101”,“010”,“001”,“110”,“101” 和 “010”。所以答案为 6。
输入包含一个门的字符串 s、一个字符串长度 k,1 ≤ |s| ≤ 10^5,1 ≤ k ≤ 100。
输出 s 中“好”的子串的数量。
本题是一个纯粹的字符串处理问题。首先,我们需要遍历 s 中所有长度为 k 的子串,看它们是否“好”;其次,我们需要找到一个高效的算法来检测是否存在子串 011。
对于长度为 k 的子串,我们有两种思路。第一种是将长度为 k 的子串都存到一个数组里,然后直接判断它们是否“好”。这种方法的空间复杂度是 O(n),其中 n 是字符串 s 的长度。第二种方法是维护一个长度为 k 的滑动窗口,窗口每次向右移动一个字符。因此,不需要开辟额外的空间来存储子串。最后,我们只需要统计计数器即可。这种方法的空间复杂度是 O(1)。
接下来,我们需要判断一个子串是否“好”。显然,如果一个子串不仅仅由 0 和 1 组成,那么它肯定不是“好”的子串。因此,如果一个子串中有非 0 和 1 的字符,我们可以直接跳过不做处理。如果所有字符都是 0 或 1,则需要进一步判断是否存在 011 子串。
为了检测是否存在 011 子串,我们可以遍历整个子串,检查相邻的三个字符是否匹配“011”的模式。如果找到了一个“011”的子串,直接跳出循环并返回 false。如果整个子串扫描完毕也没有发现“011”,则返回 true。这种方法指针只需要从头到尾扫描一遍,时间复杂度为 O(n)。
综上所述,我们可以采用滑动窗口的方法在 O(n) 的时间复杂度内解决该问题。
下面是 Python3 代码实现,以滑动窗口的方式处理“好”的子串。
def count_good_substring(s: str, k: int) -> int:
n = len(s)
cnt = 0
for i in range(n - k + 1):
# 判断子串是否“好”
if is_good(s[i:i + k]):
cnt += 1
return cnt
def is_good(sub: str) -> bool:
for i in range(len(sub)):
# 判断该子串是否由 0 和 1 组成
if sub[i] != "0" and sub[i] != "1":
return False
if i >= 2 and sub[i - 2:i + 1] == "011":
return False
return True
本题是一道较为简单的字符串处理题,主要考察了对字符串的扫描和判断能力。学会滑动窗口的使用方法可以大大提高代码效率,同时,也能够使思路更加清晰明了。