LC 3261. 统计满足 K 约束的子字符串数量 II
https://leetcode.cn/problems/count-substrings-that-satisfy-k-constraint-ii/description/
这题想了挺久的,有好几个点都是慢慢想到的:
- 对于每个位置i来说,都有一个 `end[i]` 对应,表示从i开始满足约束的话,最长到达的位置。
- 这个end是个单调非递减的数组,所以可以使用二分搜索。
- 对于query (a, b) 来说,可以分为两个区间处理:
- `[a, p]` 在这个区间里面的位置,他们的end不超过b. 所以满足这些的约束子串可以使用前缀和计算出来。
- `[p+1], b]` 在这个区间里面的位置,他们的结尾是 `b`.
class Solution:
def countKConstraintSubstrings(self, s: str, k: int, queries: List[List[int]]) -> List[int]:
n = len(s)
def build_end():
a, b = n, n
right = [n] * (n + 1)
for i in reversed(range(n)):
if s[i] == '0':
right[i] = a
a = i
else:
right[i] = b
b = i
a, b = n, n
for i in range(n):
if s[i] == '0':
a = i
break
for i in range(n):
if s[i] == '1':
b = i
break
for _ in range(k):
a = right[a]
b = right[b]
end = [-1] * n
for i in range(n):
end[i] = max(a, b)
if s[i] == '0':
a = right[a]
else:
b = right[b]
return end
end = build_end()
def search(x):
s, e = 0, n - 1
while s <= e:
m = (s + e) // 2
if end[m] <= x:
s = m + 1
else:
e = m - 1
return e
acc = [0] * (n + 1)
for i in range(n):
acc[i + 1] = acc[i] + (end[i] - i)
# print(end)
ans = []
for a, b in queries:
p = search(b + 1)
r = 0
# [a...p]
# where end[p] <= (b+1)
if p >= a:
r += acc[p + 1] - acc[a]
else:
p = a - 1
# [p + 1 .. end + 1]
# [p + 2 .. end + 1]
# [end + 1.. end + 1]
sz = (b + 1 - p)
r += (b - p) * sz - (sz - 1) * sz // 2
ans.append(r)
return ans