小J的好串问题
小M有一个只包含 '0' 和 '1' 的字符串,她想知道有多少个子串是“好串”。一个子串如果是好串,那么它的所有前缀中,'0' 的数量严格大于 '1' 的数量。
暴力思路:
首先考虑暴力解法,枚举每个子串,从每个子串起始开始统计其前缀的 '0' 和 '1' 的数量,如果'0' 的数量大于 '1' 的数量,则统计答案,如果'1' 的数量大于 '0' 的数量,因为题目要求其所有前缀中的'0' 的数量严格大于 '1' 的数量,所以对于之后的部分不用统计直接跳过。
def solution(s: str) -> int:
count = 0
n = len(s)
# 遍历所有可能的子串起始位置
for start in range(n):
zeros = 0 # 当前前缀中 '0' 的数量
ones = 0 # 当前前缀中 '1' 的数量
for end in range(start, n):
# 更新前缀中 '0' 和 '1' 的数量
if s[end] == '0':
zeros += 1
else:
ones += 1
# 检查当前前缀是否满足好串的条件
if zeros > ones:
count += 1
else:
# 一旦 '1' 的数量大于等于 '0' 的数量,则后续子串不会是好串
break
return count
if __name__ == '__main__':
print(solution("100") == 3)
print(solution("10010") == 6)
print(solution("010101") == 3)
复杂度分析
设字符串长度为n,设枚举子串左端点为 i 考虑最坏情况,则子串右端端点为n ,一次枚举长度最坏为n-i+1,时间复杂度为{O(n^2)},空间复杂度为{O(1)},则使用这种方法n一般情况最大为1e4。
优化
考虑dp,设dp[i]表示以第i个字符结尾的所有前缀中的'0' 的数量严格大于 '1' 的子串的数量。
设字符串为str,长度为n,下标从0开始。
考虑前i个字符的贡献,设其为dp[i],则总贡献为SUM(dp)
则状态转移方程
如果第i个字符为0,因为其本身可以构建一个好串,所以答案为前i-1个构建的好串数量加1
str[i]=='0' dp[i]=dp[i-1]+1
如果第i个字符为1,则这个字符可以与前面的0组合,减少好串数量,或者与前面1组合,增大要构建好串的0的数量
str[i]=='1' dp[i]=dp[i-1]-1
初始化
str[0]=='0' dp[0]=1
str[0]=='1' dp[0]=0
def solution(s: str) -> int:
length = len(s)
dp = [0] * length
if s[0] == '0':
dp[0] = 1
for i in range(1, length):
if s[i] == '0':
dp[i] = dp[i - 1] + 1
else:
dp[i] = dp[i - 1] - 1
if dp[i] < 0:
dp[i] = 0
return sum(dp)