华为OD机试题库《C++》限时优惠 9.9
华为OD机试题库《Python》限时优惠 9.9
华为OD机试题库《JavaScript》限时优惠 9.9
针对刷题难,效率慢,我们提供一对一算法辅导, 针对个人情况定制化的提高计划(全称1V1效率更高)。
看不懂有疑问需要答疑辅导欢迎私VX: code5bug
题目描述
给你一个字符串 str和整数k,返回满足以下条件的所有子字符串个数:
- 恰好包含k 个字母
- 数字0-9各出现至少一次
输入描述
第一行为字符串 str (1 <= length <= 100000),仅包含数字和小写字母。
第二行为整数k(0 <= k <= 100000)
输出描述
输出一个整数,表示满足条件的所有子字符串个数
补充说明
子字符串 是字符串中连续的 非空 字符序列
示例1
输入:
a0123456789aa
1
输出:
2
示例2
输入:
aa01234a5678901234aa
1
输出:
22
题解
- 滑动窗口法:使用两个滑动窗口来维护满足条件的子字符串。
- 窗口1(left1):指向满足恰好k个字母且所有数字0-9都出现至少一次的最早左边界。
- 窗口2(left2):指向不满足恰好k个字母且所有数字0-9都出现至少一次的最早左边界。
- 双指针维护:使用两个指针
left1
和left2
来分别维护窗口1和窗口2的左边界。- 统计数字频率:使用哈希表(或字典)来统计当前窗口中数字的出现频率,确保所有数字0-9都至少出现一次。
- 计算有效子字符串:对于每个右指针
right
,计算满足条件的子字符串的左指针范围[left1, left2)
,并将该范围内的子字符串数量累加到结果中。
Python
"""
@author: code5bug
"""
from collections import defaultdict
s = input()
k = int(input())
# 两个窗口中的字符个数计数和对应的左指针
letter_count1 = left1 = 0
letter_count2 = left2 = 0
# 对两个窗口出现的数字进行计数统计
digit_freq1, digit_freq2 = defaultdict(int), defaultdict(int)
# 满足要求的子串个数
ans = 0
for right, c in enumerate(s):
if c.isalpha():
letter_count1 += 1
letter_count2 += 1
else:
digit_freq1[c] += 1
digit_freq2[c] += 1
# 窗口形成的子串不满足要求则继续扩大窗口
if letter_count2 < k or len(digit_freq2) < 10:
continue
# 为了形成 [left1, left2) ~ right 的子串都是满足要求的子字符串
# 所以 left2 为最早不满足要求的位置
while letter_count2 >= k and len(digit_freq2) == 10:
left_char = s[left2]
left2 += 1
if left_char.isalpha():
letter_count2 -= 1
else:
if digit_freq2[left_char] == 1:
del digit_freq2[left_char]
else:
digit_freq2[left_char] -= 1
# left1 为满足要求的最早的位置
while letter_count1 > k:
left_char = s[left1]
left1 += 1
if left_char.isalpha():
letter_count1 -= 1
else:
if digit_freq1[left_char] == 1:
del digit_freq1[left_char]
else:
digit_freq1[left_char] -= 1
# left1 和 left2 之间的区间就是满足题目要求子串的左指针有效取值范围
ans += left2 - left1
print(ans)
希望这个专栏能让您熟练掌握算法, 🎁🎁🎁。
整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏